smux.c
上传用户:wxp200602
上传日期:2007-10-30
资源大小:4028k
文件大小:57k
- /*
- * Smux module authored by Rohit Dube.
- * Rewritten by Nick Amato <naamato@merit.net>.
- */
- #include <net-snmp/net-snmp-config.h>
- #include <sys/types.h>
- #include <ctype.h>
- #if HAVE_IO_H /* win32 */
- #include <io.h>
- #endif
- #include <stdio.h>
- #if HAVE_STDLIB_H
- #include <stdlib.h>
- #endif
- #if HAVE_STRING_H
- #include <string.h>
- #else
- #include <strings.h>
- #endif
- #if HAVE_UNISTD_H
- #include <unistd.h>
- #endif
- #if HAVE_ERR_H
- #include <err.h>
- #endif
- #if TIME_WITH_SYS_TIME
- # ifdef WIN32
- # include <sys/timeb.h>
- # else
- # include <sys/time.h>
- # endif
- # include <time.h>
- #else
- # if HAVE_SYS_TIME_H
- # include <sys/time.h>
- # else
- # include <time.h>
- # endif
- #endif
- #include <errno.h>
- #if HAVE_NETDB_H
- #include <netdb.h>
- #endif
- #include <sys/stat.h>
- #if HAVE_SYS_SOCKET_H
- #include <sys/socket.h>
- #elif HAVE_WINSOCK_H
- #include <winsock.h>
- #endif
- #if HAVE_SYS_FILIO_H
- #include <sys/filio.h>
- #endif
- #if HAVE_NETINET_IN_H
- #include <netinet/in.h>
- #endif
- #if HAVE_ARPA_INET_H
- #include <arpa/inet.h>
- #endif
- #if HAVE_SYS_IOCTL_H
- #include <sys/ioctl.h>
- #endif
- #include <net-snmp/net-snmp-includes.h>
- #include <net-snmp/agent/net-snmp-agent-includes.h>
- #include "smux.h"
- #include "util_funcs.h"
- #include "mibdefs.h"
- #include "snmpd.h"
- long smux_long;
- u_long smux_ulong;
- struct sockaddr_in smux_sa;
- struct counter64 smux_counter64;
- oid smux_objid[MAX_OID_LEN];
- u_char smux_str[SMUXMAXSTRLEN];
- int smux_listen_sd = -1;
- static struct timeval smux_rcv_timeout;
- static long smux_reqid;
- void init_smux(void);
- static u_char *smux_open_process(int, u_char *, size_t *, int *);
- static u_char *smux_rreq_process(int, u_char *, size_t *);
- static u_char *smux_close_process(int, u_char *, size_t *);
- static u_char *smux_trap_process(u_char *, size_t *);
- static u_char *smux_parse(u_char *, oid *, size_t *, size_t *, u_char *);
- static u_char *smux_parse_var(u_char *, size_t *, oid *, size_t *,
- size_t *, u_char *);
- static void smux_send_close(int, int);
- static void smux_list_detach(smux_reg **, smux_reg **);
- static void smux_replace_active(smux_reg *, smux_reg *);
- static void smux_peer_cleanup(int);
- static int smux_auth_peer(oid *, size_t, char *, int);
- static int smux_build(u_char, long, oid *,
- size_t *, u_char, u_char *, size_t, u_char *,
- size_t *);
- static int smux_list_add(smux_reg **, smux_reg *);
- static int smux_pdu_process(int, u_char *, size_t);
- static int smux_send_rrsp(int, int);
- static smux_reg *smux_find_match(smux_reg *, int, oid *, size_t, long);
- static smux_reg *smux_find_replacement(oid *, size_t);
- u_char *var_smux(struct variable *, oid *, size_t *, int, size_t *,
- WriteMethod ** write_method);
- int var_smux_write(int, u_char *, u_char, size_t, u_char *,
- oid *, size_t);
- static smux_reg *ActiveRegs; /* Active registrations */
- static smux_reg *PassiveRegs; /* Currently unused registrations */
- static smux_peer_auth *Auths[SMUX_MAX_PEERS]; /* Configured peers */
- static int nauths, npeers = 0;
- struct variable2 smux_variables[] = {
- /*
- * bogus entry, as in pass.c
- */
- {MIBINDEX, ASN_INTEGER, RWRITE, var_smux, 0, {MIBINDEX}},
- };
- void
- smux_parse_smux_socket(const char *token, char *cptr)
- {
- DEBUGMSGTL(("smux", "port spec: %sn", cptr));
- netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_SMUX_SOCKET, cptr);
- }
- void
- smux_parse_peer_auth(const char *token, char *cptr)
- {
- smux_peer_auth *aptr;
- if ((aptr =
- (smux_peer_auth *) calloc(1, sizeof(smux_peer_auth))) == NULL) {
- snmp_log_perror("smux_parse_peer_auth: malloc");
- return;
- }
- if (nauths == SMUX_MAX_PEERS) {
- config_perror("Too many smuxpeers");
- return;
- }
- aptr->sa_active_fd = -1;
- if (!cptr) {
- /*
- * null passwords OK
- */
- Auths[nauths++] = aptr;
- DEBUGMSGTL(("smux_conf", "null passwordn"));
- return;
- }
- /*
- * oid
- */
- aptr->sa_oid_len = MAX_OID_LEN;
- read_objid( cptr, aptr->sa_oid, &aptr->sa_oid_len );
- DEBUGMSGTL(("smux_conf", "parsing registration for: %sn", cptr));
- cptr = skip_token(cptr);
- DEBUGMSGTL(("smux_conf", "password is: %sn", cptr ? cptr : "NULL"));
- /*
- * password
- */
- if (cptr)
- strcpy(aptr->sa_passwd, cptr);
- Auths[nauths++] = aptr;
- }
- void
- smux_free_peer_auth(void)
- {
- int i;
- for (i = 0; i < nauths; i++) {
- free(Auths[i]);
- Auths[i] = NULL;
- }
- nauths = 0;
- }
- void
- init_smux(void)
- {
- snmpd_register_config_handler("smuxpeer", smux_parse_peer_auth,
- smux_free_peer_auth,
- "OID-IDENTITY PASSWORD");
- snmpd_register_config_handler("smuxsocket",
- smux_parse_smux_socket, NULL,
- "SMUX bind address");
- }
- void
- real_init_smux(void)
- {
- struct sockaddr_in lo_socket;
- char *smux_socket;
- int one = 1;
- if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE) == SUB_AGENT) {
- smux_listen_sd = -1;
- return;
- }
- /*
- * Reqid
- */
- smux_reqid = 0;
- smux_listen_sd = -1;
- /*
- * Receive timeout
- */
- smux_rcv_timeout.tv_sec = 0;
- smux_rcv_timeout.tv_usec = 500000;
- /*
- * Get ready to listen on the SMUX port
- */
- memset(&lo_socket, (0), sizeof(lo_socket));
- lo_socket.sin_family = AF_INET;
- smux_socket = netsnmp_ds_get_string(NETSNMP_DS_APPLICATION_ID,
- NETSNMP_DS_SMUX_SOCKET);
- #ifdef LOCAL_SMUX
- if (!smux_socket)
- smux_socket = "127.0.0.1"; /* By default, listen on localhost only */
- #endif
- netsnmp_sockaddr_in( &lo_socket, smux_socket, SMUXPORT );
- if ((smux_listen_sd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
- snmp_log_perror("[init_smux] socket failed");
- return;
- }
- #ifdef SO_REUSEADDR
- /*
- * At least on Linux, when the master agent terminates, any
- * TCP connections for SMUX peers are put in the TIME_WAIT
- * state for about 60 seconds. If the master agent is started
- * during this time, the bind for the listening socket will
- * fail because the SMUX port is in use.
- */
- if (setsockopt(smux_listen_sd, SOL_SOCKET, SO_REUSEADDR, (char *) &one,
- sizeof(one)) < 0) {
- snmp_log_perror("[init_smux] setsockopt(SO_REUSEADDR) failed");
- }
- #endif /* SO_REUSEADDR */
- if (bind(smux_listen_sd, (struct sockaddr *) &lo_socket,
- sizeof(lo_socket)) < 0) {
- snmp_log_perror("[init_smux] bind failed");
- close(smux_listen_sd);
- smux_listen_sd = -1;
- return;
- }
- #ifdef SO_KEEPALIVE
- if (setsockopt(smux_listen_sd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one,
- sizeof(one)) < 0) {
- snmp_log_perror("[init_smux] setsockopt(SO_KEEPALIVE) failed");
- close(smux_listen_sd);
- smux_listen_sd = -1;
- return;
- }
- #endif /* SO_KEEPALIVE */
- if (listen(smux_listen_sd, SOMAXCONN) == -1) {
- snmp_log_perror("[init_smux] listen failed");
- close(smux_listen_sd);
- smux_listen_sd = -1;
- return;
- }
- DEBUGMSGTL(("smux_init",
- "[smux_init] done; smux listen sd is %d, smux port is %dn",
- smux_listen_sd, ntohs(lo_socket.sin_port)));
- }
- u_char *
- var_smux(struct variable * vp,
- oid * name,
- size_t * length,
- int exact, size_t * var_len, WriteMethod ** write_method)
- {
- u_char *valptr, val_type;
- smux_reg *rptr;
- *write_method = var_smux_write;
- /*
- * search the active registration list
- */
- for (rptr = ActiveRegs; rptr; rptr = rptr->sr_next) {
- if (0 >= snmp_oidtree_compare(vp->name, vp->namelen, rptr->sr_name,
- rptr->sr_name_len))
- break;
- }
- if (rptr == NULL)
- return NULL;
- else if (exact && (*length < rptr->sr_name_len))
- return NULL;
- valptr = smux_snmp_process(exact, name, length,
- var_len, &val_type, rptr->sr_fd);
- if (valptr == NULL)
- return NULL;
- if ((snmp_oidtree_compare(name, *length, rptr->sr_name,
- rptr->sr_name_len)) != 0) {
- /*
- * the peer has returned a value outside
- * * of the registered tree
- */
- return NULL;
- } else {
- /*
- * set the type and return the value
- */
- vp->type = val_type;
- return valptr;
- }
- }
- int
- var_smux_write(int action,
- u_char * var_val,
- u_char var_val_type,
- size_t var_val_len,
- u_char * statP, oid * name, size_t name_len)
- {
- smux_reg *rptr;
- u_char buf[SMUXMAXPKTSIZE], *ptr, sout[3], type;
- int reterr;
- size_t var_len, datalen, name_length, packet_len;
- ssize_t len;
- long reqid, errsts, erridx;
- u_char var_type, *dataptr;
- DEBUGMSGTL(("smux", "[var_smux_write] entering var_smux_writen"));
- len = SMUXMAXPKTSIZE;
- reterr = SNMP_ERR_NOERROR;
- var_len = var_val_len;
- var_type = var_val_type;
- name_length = name_len;
- /*
- * XXX find the descriptor again
- */
- for (rptr = ActiveRegs; rptr; rptr = rptr->sr_next) {
- if (!snmp_oidtree_compare(name, name_len, rptr->sr_name,
- rptr->sr_name_len))
- break;
- }
- switch (action) {
- case RESERVE1:
- DEBUGMSGTL(("smux", "[var_smux_write] entering RESERVE1n"));
- /*
- * length might be long
- */
- var_len += (*(var_val + 1) & ASN_LONG_LEN) ?
- var_len + ((*(var_val + 1) & 0x7F) + 2) : 2;
- switch (var_val_type) {
- case ASN_INTEGER:
- case ASN_OCTET_STR:
- case ASN_COUNTER:
- case ASN_GAUGE:
- case ASN_TIMETICKS:
- case ASN_UINTEGER:
- case ASN_COUNTER64:
- case ASN_IPADDRESS:
- case ASN_OPAQUE:
- case ASN_NSAP:
- case ASN_OBJECT_ID:
- case ASN_BIT_STR:
- datalen = var_val_len;
- dataptr = var_val;
- break;
- case SNMP_NOSUCHOBJECT:
- case SNMP_NOSUCHINSTANCE:
- case SNMP_ENDOFMIBVIEW:
- case ASN_NULL:
- default:
- DEBUGMSGTL(("smux",
- "[var_smux_write] variable not supportedn"));
- return SNMP_ERR_GENERR;
- break;
- }
- if ((smux_build((u_char) SMUX_SET, smux_reqid,
- name, &name_length, var_val_type, dataptr,
- datalen, buf, &len)) < 0) {
- DEBUGMSGTL(("smux", "[var_smux_write] smux build failedn"));
- return SNMP_ERR_GENERR;
- }
- if (send(rptr->sr_fd, buf, len, 0) < 0) {
- DEBUGMSGTL(("smux", "[var_smux_write] send failedn"));
- return SNMP_ERR_GENERR;
- }
- while (1) {
- /*
- * peek at what's received
- */
- if ((len = recv(rptr->sr_fd, buf,
- SMUXMAXPKTSIZE, MSG_PEEK)) <= 0) {
- DEBUGMSGTL(("smux",
- "[var_smux_write] peek failed or timed outn"));
- /*
- * do we need to do a peer cleanup in this case??
- */
- smux_peer_cleanup(rptr->sr_fd);
- return SNMP_ERR_GENERR;
- }
- DEBUGMSGTL(("smux", "[var_smux_write] Peeked at %d bytesn",
- len));
- DEBUGDUMPSETUP("var_smux_write", buf, len);
- /*
- * determine if we received more than one packet
- */
- packet_len = len;
- ptr = asn_parse_header(buf, &packet_len, &type);
- packet_len += (ptr - buf);
- if (len > (ssize_t)packet_len) {
- /*
- * set length to receive only the first packet
- */
- len = packet_len;
- }
- /*
- * receive the first packet
- */
- if ((len = recv(rptr->sr_fd, buf, len, 0)) <= 0) {
- DEBUGMSGTL(("smux",
- "[var_smux_write] recv failed or timed outn"));
- /*
- * do we need to do a peer cleanup in this case??
- */
- smux_peer_cleanup(rptr->sr_fd);
- return SNMP_ERR_GENERR;
- }
- DEBUGMSGTL(("smux", "[var_smux_write] Received %d bytesn",
- len));
- if (buf[0] == SMUX_TRAP) {
- DEBUGMSGTL(("smux", "[var_smux_write] Received trapn"));
- snmp_log(LOG_INFO, "Got trap from peer on fd %dn",
- rptr->sr_fd);
- ptr = asn_parse_header(buf, &len, &type);
- smux_trap_process(ptr, &len);
- /*
- * go and peek at received data again
- */
- /*
- * we could receive the reply or another trap
- */
- } else {
- ptr = buf;
- ptr = asn_parse_header(ptr, &len, &type);
- if ((ptr == NULL) || type != SNMP_MSG_RESPONSE)
- return SNMP_ERR_GENERR;
- ptr =
- asn_parse_int(ptr, &len, &type, &reqid, sizeof(reqid));
- if ((ptr == NULL) || type != ASN_INTEGER)
- return SNMP_ERR_GENERR;
- ptr =
- asn_parse_int(ptr, &len, &type, &errsts,
- sizeof(errsts));
- if ((ptr == NULL) || type != ASN_INTEGER)
- return SNMP_ERR_GENERR;
- if (errsts) {
- DEBUGMSGTL(("smux",
- "[var_smux_write] errsts returnedn"));
- return (errsts);
- }
- ptr =
- asn_parse_int(ptr, &len, &type, &erridx,
- sizeof(erridx));
- if ((ptr == NULL) || type != ASN_INTEGER)
- return SNMP_ERR_GENERR;
- reterr = SNMP_ERR_NOERROR;
- break;
- }
- } /* while (1) */
- break; /* case Action == RESERVE1 */
- case RESERVE2:
- DEBUGMSGTL(("smux", "[var_smux_write] entering RESERVE2n"));
- reterr = SNMP_ERR_NOERROR;
- break; /* case Action == RESERVE2 */
- case FREE:
- case COMMIT:
- ptr = sout;
- *(ptr++) = (u_char) SMUX_SOUT;
- *(ptr++) = (u_char) 1;
- if (action == FREE) {
- *ptr = (u_char) 1; /* rollback */
- DEBUGMSGTL(("smux",
- "[var_smux_write] entering FREE - sending RollBack n"));
- } else {
- *ptr = (u_char) 0; /* commit */
- DEBUGMSGTL(("smux",
- "[var_smux_write] entering FREE - sending Commit n"));
- }
- if ((send(rptr->sr_fd, sout, 3, 0)) < 0) {
- DEBUGMSGTL(("smux",
- "[var_smux_write] send rollback/commit failedn"));
- return SNMP_ERR_GENERR;
- }
- reterr = SNMP_ERR_NOERROR;
- break; /* case Action == COMMIT */
- default:
- break;
- }
- return reterr;
- }
- int
- smux_accept(int sd)
- {
- u_char data[SMUXMAXPKTSIZE], *ptr, type;
- struct sockaddr_in in_socket;
- struct timeval tv;
- int fail, fd, alen;
- int length;
- ssize_t len;
- alen = sizeof(struct sockaddr_in);
- /*
- * this may be too high
- */
- tv.tv_sec = 5;
- tv.tv_usec = 0;
- /*
- * connection request
- */
- DEBUGMSGTL(("smux", "[smux_accept] Calling accept()n"));
- errno = 0;
- if ((fd = accept(sd, (struct sockaddr *) &in_socket, &alen)) < 0) {
- snmp_log_perror("[smux_accept] accept failed");
- return -1;
- } else {
- snmp_log(LOG_INFO, "[smux_accept] accepted fd %d from %s:%dn",
- fd, inet_ntoa(in_socket.sin_addr),
- ntohs(in_socket.sin_port));
- if (npeers + 1 == SMUXMAXPEERS) {
- snmp_log(LOG_ERR,
- "[smux_accept] denied peer on fd %d, limit %d reached",
- fd, SMUXMAXPEERS);
- close(sd);
- return -1;
- }
- /*
- * now block for an OpenPDU
- */
- if ((length = recv(fd, (char *) data, SMUXMAXPKTSIZE, 0)) <= 0) {
- DEBUGMSGTL(("smux",
- "[smux_accept] peer on fd %d died or timed outn",
- fd));
- close(fd);
- return -1;
- }
- /*
- * try to authorize him
- */
- ptr = data;
- len = length;
- if ((ptr = asn_parse_header(ptr, &len, &type)) == NULL) {
- smux_send_close(fd, SMUXC_PACKETFORMAT);
- close(fd);
- DEBUGMSGTL(("smux", "[smux_accept] peer on %d sent bad open"));
- return -1;
- } else if (type != (u_char) SMUX_OPEN) {
- smux_send_close(fd, SMUXC_PROTOCOLERROR);
- close(fd);
- DEBUGMSGTL(("smux",
- "[smux_accept] peer on %d did not send open: (%d)n",
- type));
- return -1;
- }
- ptr = smux_open_process(fd, ptr, &len, &fail);
- if (fail) {
- smux_send_close(fd, SMUXC_AUTHENTICATIONFAILURE);
- close(fd);
- DEBUGMSGTL(("smux",
- "[smux_accept] peer on %d failed authenticationn",
- fd));
- return -1;
- }
- /*
- * he's OK
- */
- #ifdef SO_RCVTIMEO
- if (setsockopt
- (fd, SOL_SOCKET, SO_RCVTIMEO, (void *) &tv, sizeof(tv)) < 0) {
- DEBUGMSGTL(("smux",
- "[smux_accept] setsockopt(SO_RCVTIMEO) failed fd %dn",
- fd));
- snmp_log_perror("smux_accept: setsockopt SO_RCVTIMEO");
- }
- #endif
- npeers++;
- DEBUGMSGTL(("smux", "[smux_accept] fd %dn", fd));
- /*
- * Process other PDUs already read, e.g. a registerRequest.
- */
- len = length - (ptr - data);
- if (smux_pdu_process(fd, ptr, len) < 0) {
- /*
- * Easy come, easy go. Clean-up is already done.
- */
- return -1;
- }
- }
- return fd;
- }
- int
- smux_process(int fd)
- {
- int length;
- u_char data[SMUXMAXPKTSIZE];
- length = recv(fd, (char *) data, SMUXMAXPKTSIZE, 0);
- if (length <= 0) {
- /*
- * the peer went away, close this descriptor
- * * and delete it from the list
- */
- DEBUGMSGTL(("smux",
- "[smux_process] peer on fd %d died or timed outn",
- fd));
- smux_peer_cleanup(fd);
- return -1;
- }
- return smux_pdu_process(fd, data, length);
- }
- static int
- smux_pdu_process(int fd, u_char * data, size_t length)
- {
- int error;
- size_t len;
- u_char *ptr, type;
- DEBUGMSGTL(("smux", "[smux_pdu_process] Processing %d bytesn",
- length));
- error = 0;
- ptr = data;
- while (error == 0 && ptr != NULL && ptr < data + length) {
- len = length - (ptr - data);
- ptr = asn_parse_header(ptr, &len, &type);
- DEBUGMSGTL(("smux", "[smux_pdu_process] type is %dn",
- (int) type));
- switch (type) {
- case SMUX_OPEN:
- smux_send_close(fd, SMUXC_PROTOCOLERROR);
- DEBUGMSGTL(("smux",
- "[smux_pdu_process] peer on fd %d sent duplicate open?n",
- fd));
- smux_peer_cleanup(fd);
- error = -1;
- break;
- case SMUX_CLOSE:
- ptr = smux_close_process(fd, ptr, &len);
- smux_peer_cleanup(fd);
- error = -1;
- break;
- case SMUX_RREQ:
- ptr = smux_rreq_process(fd, ptr, &len);
- break;
- case SMUX_RRSP:
- error = -1;
- smux_send_close(fd, SMUXC_PROTOCOLERROR);
- smux_peer_cleanup(fd);
- DEBUGMSGTL(("smux",
- "[smux_pdu_process] peer on fd %d sent RRSP!n",
- fd));
- break;
- case SMUX_SOUT:
- error = -1;
- smux_send_close(fd, SMUXC_PROTOCOLERROR);
- smux_peer_cleanup(fd);
- DEBUGMSGTL(("smux", "This shouldn't have happened!n"));
- break;
- case SMUX_TRAP:
- snmp_log(LOG_INFO, "Got trap from peer on fd %dn", fd);
- ptr = smux_trap_process(ptr, &len);
- /*
- * watch out for close on top of this...should return correct end
- */
- /*
- * debug this...
- */
- ptr = NULL;
- break;
- default:
- smux_send_close(fd, SMUXC_PACKETFORMAT);
- smux_peer_cleanup(fd);
- DEBUGMSGTL(("smux", "[smux_pdu_process] Wrong type %dn",
- (int) type));
- error = -1;
- break;
- }
- }
- return error;
- }
- static u_char *
- smux_open_process(int fd, u_char * ptr, size_t * len, int *fail)
- {
- u_char type;
- long version;
- oid oid_name[MAX_OID_LEN];
- char passwd[SMUXMAXSTRLEN];
- char descr[SMUXMAXSTRLEN];
- char oid_print[SMUXMAXSTRLEN];
- int i;
- size_t oid_name_len, string_len;
- if (!(ptr = asn_parse_int(ptr, len, &type, &version, sizeof(version)))) {
- DEBUGMSGTL(("smux", "[smux_open_process] version parse failedn"));
- *fail = TRUE;
- return ((ptr += *len));
- }
- DEBUGMSGTL(("smux",
- "[smux_open_process] version %d, len %d, type %dn",
- version, *len, (int) type));
- oid_name_len = MAX_OID_LEN;
- if ((ptr = asn_parse_objid(ptr, len, &type, oid_name,
- &oid_name_len)) == NULL) {
- DEBUGMSGTL(("smux", "[smux_open_process] oid parse failedn"));
- *fail = TRUE;
- return ((ptr += *len));
- }
- snprint_objid(oid_print, sizeof(oid_print), oid_name, oid_name_len);
- if (snmp_get_do_debugging()) {
- DEBUGMSGTL(("smux", "[smux_open_process] smux peer: %sn",
- oid_print));
- DEBUGMSGTL(("smux", "[smux_open_process] len %d, type %dn", *len,
- (int) type));
- }
- string_len = SMUXMAXSTRLEN;
- if ((ptr = asn_parse_string(ptr, len, &type, (u_char *) descr,
- &string_len)) == NULL) {
- DEBUGMSGTL(("smux", "[smux_open_process] descr parse failedn"));
- *fail = TRUE;
- return ((ptr += *len));
- }
- if (snmp_get_do_debugging()) {
- DEBUGMSGTL(("smux", "[smux_open_process] smux peer descr: "));
- for (i = 0; i < (int) string_len; i++)
- DEBUGMSG(("smux", "%c", descr[i]));
- DEBUGMSG(("smux", "n"));
- DEBUGMSGTL(("smux", "[smux_open_process] len %d, type %dn", *len,
- (int) type));
- }
- descr[string_len] = 0;
- string_len = SMUXMAXSTRLEN;
- if ((ptr = asn_parse_string(ptr, len, &type, (u_char *) passwd,
- &string_len)) == NULL) {
- DEBUGMSGTL(("smux", "[smux_open_process] passwd parse failedn"));
- *fail = TRUE;
- return ((ptr += *len));
- }
- if (snmp_get_do_debugging()) {
- DEBUGMSGTL(("smux", "[smux_open_process] smux peer passwd: "));
- for (i = 0; i < (int) string_len; i++)
- DEBUGMSG(("smux", "%c", passwd[i]));
- DEBUGMSG(("smux", "n"));
- DEBUGMSGTL(("smux", "[smux_open_process] len %d, type %dn", *len,
- (int) type));
- }
- passwd[string_len] = ' ';
- if (!smux_auth_peer(oid_name, oid_name_len, passwd, fd)) {
- snmp_log(LOG_WARNING,
- "refused smux peer: oid %s, descr %sn",
- oid_print, descr);
- *fail = TRUE;
- return ptr;
- }
- snmp_log(LOG_INFO,
- "accepted smux peer: oid %s, descr %sn",
- oid_print, descr);
- *fail = FALSE;
- return ptr;
- }
- static void
- smux_send_close(int fd, int reason)
- {
- u_char outpacket[3], *ptr;
- ptr = outpacket;
- *(ptr++) = (u_char) SMUX_CLOSE;
- *(ptr++) = (u_char) 1;
- *ptr = (u_char) (reason & 0xFF);
- if (snmp_get_do_debugging())
- DEBUGMSGTL(("smux",
- "[smux_close] sending close to fd %d, reason %dn", fd,
- reason));
- /*
- * send a response back
- */
- if (send(fd, (char *) outpacket, 3, 0) < 0) {
- snmp_log_perror("[smux_snmp_close] send failed");
- }
- }
- static int
- smux_auth_peer(oid * name, size_t namelen, char *passwd, int fd)
- {
- int i;
- for (i = 0; i < nauths; i++) {
- if (snmp_oid_compare(Auths[i]->sa_oid, Auths[i]->sa_oid_len,
- name, namelen) == 0) {
- if (!(strcmp(Auths[i]->sa_passwd, passwd)) &&
- (Auths[i]->sa_active_fd == -1)) {
- /*
- * matched, mark the auth
- */
- Auths[i]->sa_active_fd = fd;
- return 1;
- }
- }
- }
- /*
- * did not match oid and passwd
- */
- return 0;
- }
- /*
- * XXX - Bells and Whistles:
- * Need to catch signal when snmpd goes down and send close pdu to gated
- */
- static u_char *
- smux_close_process(int fd, u_char * ptr, size_t * len)
- {
- long down = 0;
- int length = *len;
- /*
- * This is the integer part of the close pdu
- */
- while (length--) {
- down = (down << 8) | (long) *ptr;
- ptr++;
- }
- DEBUGMSGTL(("smux",
- "[smux_close_process] close from peer on fd %d reason %dn",
- fd, down));
- smux_peer_cleanup(fd);
- return NULL;
- }
- static u_char *
- smux_rreq_process(int sd, u_char * ptr, size_t * len)
- {
- long priority, rpriority;
- long operation;
- oid oid_name[MAX_OID_LEN];
- size_t oid_name_len;
- int i, result;
- u_char type;
- smux_reg *rptr, *nrptr;
- oid_name_len = MAX_OID_LEN;
- ptr = asn_parse_objid(ptr, len, &type, oid_name, &oid_name_len);
- DEBUGMSGTL(("smux", "[smux_rreq_process] smux subtree: "));
- DEBUGMSGOID(("smux", oid_name, oid_name_len));
- DEBUGMSG(("smux", "n"));
- if ((ptr = asn_parse_int(ptr, len, &type, &priority,
- sizeof(priority))) == NULL) {
- DEBUGMSGTL(("smux",
- "[smux_rreq_process] priority parse failedn"));
- smux_send_rrsp(sd, -1);
- return NULL;
- }
- DEBUGMSGTL(("smux", "[smux_rreq_process] priority %dn", priority));
- if ((ptr = asn_parse_int(ptr, len, &type, &operation,
- sizeof(operation))) == NULL) {
- DEBUGMSGTL(("smux",
- "[smux_rreq_process] operation parse failedn"));
- smux_send_rrsp(sd, -1);
- return NULL;
- }
- DEBUGMSGTL(("smux", "[smux_rreq_process] operation %dn", operation));
- if (operation == SMUX_REGOP_DELETE) {
- /*
- * search the active list for this registration
- */
- rptr =
- smux_find_match(ActiveRegs, sd, oid_name, oid_name_len,
- priority);
- if (rptr) {
- rpriority = rptr->sr_priority;
- /*
- * unregister the mib
- */
- unregister_mib(rptr->sr_name, rptr->sr_name_len);
- /*
- * find a replacement
- */
- nrptr =
- smux_find_replacement(rptr->sr_name, rptr->sr_name_len);
- if (nrptr) {
- /*
- * found one
- */
- smux_replace_active(rptr, nrptr);
- } else {
- /*
- * no replacement found
- */
- smux_list_detach(&ActiveRegs, &rptr);
- free(rptr);
- }
- smux_send_rrsp(sd, rpriority);
- return ptr;
- }
- /*
- * search the passive list for this registration
- */
- rptr =
- smux_find_match(PassiveRegs, sd, oid_name, oid_name_len,
- priority);
- if (rptr) {
- rpriority = rptr->sr_priority;
- smux_list_detach(&PassiveRegs, &rptr);
- free(rptr);
- smux_send_rrsp(sd, rpriority);
- return ptr;
- }
- /*
- * This peer cannot unregister the tree, it does not
- * * belong to him. Send him an error.
- */
- smux_send_rrsp(sd, -1);
- return ptr;
- } else if ((operation == SMUX_REGOP_REGISTER_RO) ||
- (operation == SMUX_REGOP_REGISTER_RW)) {
- if (priority < -1) {
- DEBUGMSGTL(("smux",
- "[smux_rreq_process] peer fd %d invalid priority",
- sd, priority));
- smux_send_rrsp(sd, -1);
- return NULL;
- }
- if ((nrptr = malloc(sizeof(smux_reg))) == NULL) {
- snmp_log_perror("[smux_rreq_process] malloc");
- smux_send_rrsp(sd, -1);
- return NULL;
- }
- nrptr->sr_priority = priority;
- nrptr->sr_name_len = oid_name_len;
- nrptr->sr_fd = sd;
- for (i = 0; i < (int) oid_name_len; i++)
- nrptr->sr_name[i] = oid_name[i];
- /*
- * See if this tree matches or scopes any of the
- * * active trees.
- */
- for (rptr = ActiveRegs; rptr; rptr = rptr->sr_next) {
- result =
- snmp_oid_compare(oid_name, oid_name_len, rptr->sr_name,
- rptr->sr_name_len);
- if (result == 0) {
- if ((oid_name_len == rptr->sr_name_len)) {
- if ((nrptr->sr_priority == -1)) {
- nrptr->sr_priority = rptr->sr_priority;
- do {
- nrptr->sr_priority++;
- } while (smux_list_add(&PassiveRegs, nrptr));
- goto done;
- } else if (nrptr->sr_priority < rptr->sr_priority) {
- /*
- * Better priority. There are no better
- * * priorities for this tree in the passive list,
- * * so replace the current active tree.
- */
- smux_replace_active(rptr, nrptr);
- goto done;
- } else {
- /*
- * Equal or worse priority
- */
- do {
- nrptr->sr_priority++;
- } while (smux_list_add(&PassiveRegs, nrptr) == -1);
- goto done;
- }
- } else if (oid_name_len < rptr->sr_name_len) {
- /*
- * This tree scopes a current active
- * * tree. Replace the current active tree.
- */
- smux_replace_active(rptr, nrptr);
- goto done;
- } else { /* oid_name_len > rptr->sr_name_len */
- /*
- * This tree is scoped by a current
- * * active tree.
- */
- do {
- nrptr->sr_priority++;
- } while (smux_list_add(&PassiveRegs, nrptr) == -1);
- goto done;
- }
- }
- }
- /*
- * We didn't find it in the active list. Add it at
- * * the requested priority.
- */
- if (nrptr->sr_priority == -1)
- nrptr->sr_priority = 0;
- smux_list_add(&ActiveRegs, nrptr);
- register_mib("smux", (struct variable *)
- smux_variables, sizeof(struct variable2),
- 1, nrptr->sr_name, nrptr->sr_name_len);
- done:
- smux_send_rrsp(sd, nrptr->sr_priority);
- return ptr;
- } else {
- DEBUGMSGTL(("smux", "[smux_rreq_process] unknown operationn"));
- smux_send_rrsp(sd, -1);
- return NULL;
- }
- }
- /*
- * Find the registration with a matching descriptor, OID and priority. If
- * the priority is -1 then find a registration with a matching descriptor,
- * a matching OID, and the highest priority.
- */
- static smux_reg *
- smux_find_match(smux_reg * regs, int sd, oid * oid_name,
- size_t oid_name_len, long priority)
- {
- smux_reg *rptr, *bestrptr;
- bestrptr = NULL;
- for (rptr = regs; rptr; rptr = rptr->sr_next) {
- if (rptr->sr_fd != sd)
- continue;
- if (snmp_oid_compare
- (rptr->sr_name, rptr->sr_name_len, oid_name, oid_name_len))
- continue;
- if (rptr->sr_priority == priority)
- return rptr;
- if (priority != -1)
- continue;
- if (bestrptr) {
- if (bestrptr->sr_priority > rptr->sr_priority)
- bestrptr = rptr;
- } else {
- bestrptr = rptr;
- }
- }
- return bestrptr;
- }
- static void
- smux_replace_active(smux_reg * actptr, smux_reg * pasptr)
- {
- smux_list_detach(&ActiveRegs, &actptr);
- unregister_mib(actptr->sr_name, actptr->sr_name_len);
- smux_list_detach(&PassiveRegs, &pasptr);
- (void) smux_list_add(&ActiveRegs, pasptr);
- register_mib("smux", (struct variable *) smux_variables,
- sizeof(struct variable2), 1, pasptr->sr_name,
- pasptr->sr_name_len);
- free(actptr);
- }
- static void
- smux_list_detach(smux_reg ** head, smux_reg ** m_remove)
- {
- smux_reg *rptr, *rptr2;
- if (*head == NULL) {
- DEBUGMSGTL(("smux", "[smux_list_detach] Ouch!"));
- return;
- }
- if (*head == *m_remove) {
- *m_remove = *head;
- *head = (*head)->sr_next;
- return;
- }
- for (rptr = *head, rptr2 = rptr->sr_next; rptr2;
- rptr2 = rptr2->sr_next, rptr = rptr->sr_next) {
- if (rptr2 == *m_remove) {
- *m_remove = rptr2;
- rptr->sr_next = rptr2->sr_next;
- return;
- }
- }
- }
- /*
- * Attempt to add a registration (in order) to a list. If the
- * add fails (because of an existing registration with equal
- * priority) return -1.
- */
- static int
- smux_list_add(smux_reg ** head, smux_reg * add)
- {
- smux_reg *rptr;
- int result;
- if (*head == NULL) {
- *head = add;
- (*head)->sr_next = NULL;
- return 0;
- }
- for (rptr = *head; rptr->sr_next; rptr = rptr->sr_next) {
- result = snmp_oid_compare(add->sr_name, add->sr_name_len,
- rptr->sr_name, rptr->sr_name_len);
- if ((result == 0) && (add->sr_priority == rptr->sr_priority)) {
- /*
- * same tree, same pri, nope
- */
- return -1;
- } else if (result < 0) {
- /*
- * this can only happen if we go before the head
- */
- add->sr_next = *head;
- *head = add;
- return 0;
- } else if ((snmp_oid_compare(add->sr_name, add->sr_name_len,
- rptr->sr_next->sr_name,
- rptr->sr_next->sr_name_len)) < 0) {
- /*
- * insert here
- */
- add->sr_next = rptr->sr_next;
- rptr->sr_next = add;
- return 0;
- }
- }
- /*
- * compare the last one
- */
- if ((snmp_oid_compare(add->sr_name, add->sr_name_len, rptr->sr_name,
- rptr->sr_name_len) == 0)
- && add->sr_priority == rptr->sr_priority)
- return -1;
- else {
- rptr->sr_next = add;
- add->sr_next = NULL;
- }
- return 0;
- }
- /*
- * Find a replacement for this registration. In order
- * of preference:
- *
- * - Least difference in subtree length
- * - Best (lowest) priority
- *
- * For example, if we need to replace .1.3.6.1.69,
- * we would pick .1.3.6.1.69.1 instead of .1.3.6.69.1.1
- *
- */
- static smux_reg *
- smux_find_replacement(oid * name, size_t name_len)
- {
- smux_reg *rptr, *bestptr;
- int bestlen, difflen;
- bestlen = SMUX_MAX_PRIORITY;
- bestptr = NULL;
- for (rptr = PassiveRegs; rptr; rptr = rptr->sr_next) {
- if (!snmp_oidtree_compare(rptr->sr_name, rptr->sr_name_len,
- name, name_len)) {
- if ((difflen = rptr->sr_name_len - name_len)
- < bestlen) {
- bestlen = difflen;
- bestptr = rptr;
- } else if ((difflen == bestlen) &&
- (rptr->sr_priority < bestptr->sr_priority))
- bestptr = rptr;
- }
- }
- return bestptr;
- }
- u_char *
- smux_snmp_process(int exact,
- oid * objid,
- size_t * len,
- size_t * return_len, u_char * return_type, int sd)
- {
- u_char packet[SMUXMAXPKTSIZE], *ptr, result[SMUXMAXPKTSIZE];
- size_t length = SMUXMAXPKTSIZE;
- u_char type;
- size_t packet_len;
- /*
- * Send the query to the peer
- */
- smux_reqid++;
- if (exact)
- type = SMUX_GET;
- else
- type = SMUX_GETNEXT;
- if (smux_build(type, smux_reqid, objid, len, 0, NULL,
- *len, packet, &length) < 0) {
- snmp_log(LOG_ERR, "[smux_snmp_process]: smux_build failedn");
- return NULL;
- }
- DEBUGMSGTL(("smux", "[smux_snmp_process] oid from build: "));
- DEBUGMSGOID(("smux", objid, *len));
- DEBUGMSG(("smux", "n"));
- if (send(sd, (char *) packet, length, 0) < 0) {
- snmp_log_perror("[smux_snmp_process] send failed");
- }
- DEBUGMSGTL(("smux",
- "[smux_snmp_process] Sent %d request to peer; %d bytesn",
- (int) type, length));
- while (1) {
- /*
- * peek at what's received
- */
- length = recv(sd, (char *) result, SMUXMAXPKTSIZE, MSG_PEEK);
- if (length < 0) {
- snmp_log_perror("[smux_snmp_process] peek failed");
- smux_peer_cleanup(sd);
- return NULL;
- }
- DEBUGMSGTL(("smux", "[smux_snmp_process] Peeked at %d bytesn",
- length));
- DEBUGDUMPSETUP("smux_snmp_process", result, length);
- /*
- * determine if we received more than one packet
- */
- packet_len = length;
- ptr = asn_parse_header(result, &packet_len, &type);
- packet_len += (ptr - result);
- if (length > packet_len) {
- /*
- * set length to receive only the first packet
- */
- length = packet_len;
- }
- /*
- * receive the first packet
- */
- length = recv(sd, (char *) result, length, 0);
- if (length < 0) {
- snmp_log_perror("[smux_snmp_process] recv failed");
- smux_peer_cleanup(sd);
- return NULL;
- }
- DEBUGMSGTL(("smux", "[smux_snmp_process] Received %d bytesn",
- length));
- if (result[0] == SMUX_TRAP) {
- DEBUGMSGTL(("smux", "[smux_snmp_process] Received trapn"));
- snmp_log(LOG_INFO, "Got trap from peer on fd %dn", sd);
- ptr = asn_parse_header(result, &length, &type);
- smux_trap_process(ptr, &length);
- /*
- * go and peek at received data again
- */
- /*
- * we could receive the reply or another trap
- */
- } else {
- /*
- * Interpret reply
- */
- ptr = smux_parse(result, objid, len, return_len, return_type);
- /*
- * ptr will point to query result or NULL if error
- */
- break;
- }
- } /* while (1) */
- return ptr;
- }
- static u_char *
- smux_parse(u_char * rsp,
- oid * objid,
- size_t * oidlen, size_t * return_len, u_char * return_type)
- {
- size_t length = SMUXMAXPKTSIZE;
- u_char *ptr, type;
- long reqid, errstat, errindex;
- ptr = rsp;
- /*
- * Return pointer to the snmp/smux return value.
- * return_len should contain the number of bytes in the value
- * returned above.
- * objid is the next object, with len for GETNEXT.
- * objid and len are not changed for GET
- */
- ptr = asn_parse_header(ptr, &length, &type);
- if (ptr == NULL || type != SNMP_MSG_RESPONSE)
- return NULL;
- if ((ptr = asn_parse_int(ptr, &length, &type, &reqid,
- sizeof(reqid))) == NULL) {
- DEBUGMSGTL(("smux", "[smux_parse] parse of reqid failedn"));
- return NULL;
- }
- if ((ptr = asn_parse_int(ptr, &length, &type, &errstat,
- sizeof(errstat))) == NULL) {
- DEBUGMSGTL(("smux",
- "[smux_parse] parse of error status failedn"));
- return NULL;
- }
- if ((ptr = asn_parse_int(ptr, &length, &type, &errindex,
- sizeof(errindex))) == NULL) {
- DEBUGMSGTL(("smux", "[smux_parse] parse of error index failedn"));
- return NULL;
- }
- /*
- * XXX How to send something intelligent back in case of an error
- */
- DEBUGMSGTL(("smux",
- "[smux_parse] Message type %d, reqid %d, errstat %d, nterrindex %dn",
- (int) type, reqid, errstat, errindex));
- if (ptr == NULL || errstat != SNMP_ERR_NOERROR)
- return NULL;
- /*
- * stuff to return
- */
- return (smux_parse_var
- (ptr, &length, objid, oidlen, return_len, return_type));
- }
- static u_char *
- smux_parse_var(u_char * varbind,
- size_t * varbindlength,
- oid * objid,
- size_t * oidlen, size_t * varlength, u_char * vartype)
- {
- oid var_name[MAX_OID_LEN];
- size_t var_name_len;
- size_t var_val_len;
- u_char *var_val;
- size_t str_len, objid_len;
- size_t len;
- u_char *ptr;
- u_char type;
- ptr = varbind;
- len = *varbindlength;
- DEBUGMSGTL(("smux", "[smux_parse_var] before any processing: "));
- DEBUGMSGOID(("smux", objid, *oidlen));
- DEBUGMSG(("smux", "n"));
- ptr = asn_parse_header(ptr, &len, &type);
- if (ptr == NULL || type != (ASN_SEQUENCE | ASN_CONSTRUCTOR)) {
- snmp_log(LOG_NOTICE, "[smux_parse_var] Panic: type %dn",
- (int) type);
- return NULL;
- }
- /*
- * get hold of the objid and the asn1 coded value
- */
- var_name_len = MAX_OID_LEN;
- ptr = snmp_parse_var_op(ptr, var_name, &var_name_len, vartype,
- &var_val_len, &var_val, &len);
- *oidlen = var_name_len;
- memcpy(objid, var_name, var_name_len * sizeof(oid));
- DEBUGMSGTL(("smux", "[smux_parse_var] returning oid : "));
- DEBUGMSGOID(("smux", objid, *oidlen));
- DEBUGMSG(("smux", "n"));
- /*
- * XXX
- */
- len = SMUXMAXPKTSIZE;
- DEBUGMSGTL(("smux",
- "[smux_parse_var] Asn coded len of var %d, type %dn",
- var_val_len, (int) *vartype));
- switch ((short) *vartype) {
- case ASN_INTEGER:
- *varlength = sizeof(long);
- asn_parse_int(var_val, &len, vartype,
- (long *) &smux_long, *varlength);
- return (u_char *) & smux_long;
- break;
- case ASN_COUNTER:
- case ASN_GAUGE:
- case ASN_TIMETICKS:
- case ASN_UINTEGER:
- *varlength = sizeof(u_long);
- asn_parse_unsigned_int(var_val, &len, vartype,
- (u_long *) & smux_ulong, *varlength);
- return (u_char *) & smux_ulong;
- break;
- case ASN_COUNTER64:
- *varlength = sizeof(smux_counter64);
- asn_parse_unsigned_int64(var_val, &len, vartype,
- (struct counter64 *) &smux_counter64,
- *varlength);
- return (u_char *) & smux_counter64;
- break;
- case ASN_IPADDRESS:
- *varlength = 4;
- /*
- * consume the tag and length, but just copy here
- * because we know it is an ip address
- */
- if ((var_val = asn_parse_header(var_val, &len, &type)) == NULL)
- return NULL;
- memcpy((u_char *) & (smux_sa.sin_addr.s_addr), var_val,
- *varlength);
- return (u_char *) & (smux_sa.sin_addr.s_addr);
- break;
- case ASN_OCTET_STR:
- /*
- * XXX
- */
- if (len == 0)
- return NULL;
- str_len = SMUXMAXSTRLEN;
- asn_parse_string(var_val, &len, vartype, smux_str, &str_len);
- *varlength = str_len;
- return smux_str;
- break;
- case ASN_OPAQUE:
- case ASN_NSAP:
- case ASN_OBJECT_ID:
- objid_len = MAX_OID_LEN;
- asn_parse_objid(var_val, &len, vartype, smux_objid, &objid_len);
- *varlength = objid_len * sizeof(oid);
- return (u_char *) smux_objid;
- break;
- case SNMP_NOSUCHOBJECT:
- case SNMP_NOSUCHINSTANCE:
- case SNMP_ENDOFMIBVIEW:
- case ASN_NULL:
- return NULL;
- break;
- case ASN_BIT_STR:
- /*
- * XXX
- */
- if (len == 0)
- return NULL;
- str_len = SMUXMAXSTRLEN;
- asn_parse_bitstring(var_val, &len, vartype, smux_str, &str_len);
- *varlength = str_len;
- return (u_char *) smux_str;
- break;
- default:
- snmp_log(LOG_ERR, "bad type returned (%x)n", *vartype);
- return NULL;
- break;
- }
- }
- /*
- * XXX This is a bad hack - do not want to muck with ucd code
- */
- static int
- smux_build(u_char type,
- long reqid,
- oid * objid,
- size_t * oidlen,
- u_char val_type,
- u_char * val, size_t val_len, u_char * packet, size_t * length)
- {
- u_char *ptr, *save1, *save2;
- size_t len;
- long errstat = 0;
- long errindex = 0;
- /*
- * leave space for Seq and length
- */
- save1 = packet;
- ptr = packet + 4;
- len = *length - 4;
- /*
- * build reqid
- */
- ptr = asn_build_int(ptr, &len,
- (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
- ASN_INTEGER), &reqid,
- sizeof(reqid));
- if (ptr == NULL) {
- return -1;
- }
- /*
- * build err stat
- */
- ptr = asn_build_int(ptr, &len,
- (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
- ASN_INTEGER), &errstat, sizeof(errstat));
- if (ptr == NULL) {
- return -1;
- }
- /*
- * build err index
- */
- ptr = asn_build_int(ptr, &len,
- (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
- ASN_INTEGER), &errindex,
- sizeof(errindex));
- if (ptr == NULL) {
- return -1;
- }
- save2 = ptr;
- ptr += 4;
- len -= 4;
- if (type != SMUX_SET) {
- val_type = ASN_NULL;
- val_len = 0;
- }
- /*
- * build var list : snmp_build_var_op not liked by gated XXX
- */
- ptr = snmp_build_var_op(ptr, objid, oidlen, val_type, val_len,
- val, &len);
- if (ptr == NULL) {
- return -1;
- }
- len = ptr - save1;
- asn_build_sequence(save1, &len, type, (ptr - save1 - 4));
- len = ptr - save2;
- asn_build_sequence(save2, &len,
- (ASN_SEQUENCE | ASN_CONSTRUCTOR),
- (ptr - save2 - 4));
- *length = ptr - packet;
- return 0;
- }
- static void
- smux_peer_cleanup(int sd)
- {
- smux_reg *nrptr, *rptr, *rptr2;
- int nfound, i;
- nfound = 0;
- /*
- * close the descriptor
- */
- close(sd);
- /*
- * delete all of the passive registrations that this peer owns
- */
- for (rptr = PassiveRegs; rptr; rptr = nrptr) {
- nrptr = rptr->sr_next;
- if (rptr->sr_fd == sd) {
- smux_list_detach(&PassiveRegs, &rptr);
- free(rptr);
- }
- rptr = nrptr;
- }
- /*
- * find replacements for all of the active registrations found
- */
- for (rptr = ActiveRegs; rptr; rptr = rptr2) {
- rptr2 = rptr->sr_next;
- if (rptr->sr_fd == sd) {
- smux_list_detach(&ActiveRegs, &rptr);
- unregister_mib(rptr->sr_name, rptr->sr_name_len);
- if ((nrptr = smux_find_replacement(rptr->sr_name,
- rptr->sr_name_len)) !=
- NULL) {
- smux_list_detach(&PassiveRegs, &nrptr);
- smux_list_add(&ActiveRegs, nrptr);
- register_mib("smux", (struct variable *)
- smux_variables, sizeof(struct variable2),
- 1, nrptr->sr_name, nrptr->sr_name_len);
- }
- free(rptr);
- }
- }
- /*
- * decrement the peer count
- */
- npeers--;
- /*
- * make his auth available again
- */
- for (i = 0; i < nauths; i++) {
- if (Auths[i]->sa_active_fd == sd) {
- char oid_name[128];
- Auths[i]->sa_active_fd = -1;
- snprint_objid(oid_name, sizeof(oid_name), Auths[i]->sa_oid,
- Auths[i]->sa_oid_len);
- snmp_log(LOG_INFO, "peer disconnected: %sn", oid_name);
- }
- }
- }
- int
- smux_send_rrsp(int sd, int pri)
- {
- u_char outdata[2 + sizeof(int)];
- u_char *ptr = outdata;
- int intsize = sizeof(int);
- u_int mask = ((u_int) 0xFF) << (8 * (sizeof(int) - 1));
- /*
- * e.g. mask is 0xFF000000 on a 32-bit machine
- */
- int sent;
- /*
- * This is kind of like calling asn_build_int(), but the
- * encoding will always be the size of an integer on this
- * machine, never shorter.
- */
- *ptr++ = (u_char) SMUX_RRSP;
- *ptr++ = (u_char) intsize;
- /*
- * Copy each byte, most significant first.
- */
- while (intsize--) {
- *ptr++ = (u_char) ((pri & mask) >> (8 * (sizeof(int) - 1)));
- pri <<= 8;
- }
- sent = send(sd, (char *) outdata, sizeof outdata, 0);
- if (sent < 0) {
- DEBUGMSGTL(("smux", "[smux_send_rrsp] send failedn"));
- }
- return (sent);
- }
- static u_char *
- smux_trap_process(u_char * rsp, size_t * len)
- {
- oid sa_enterpriseoid[MAX_OID_LEN], var_name[MAX_OID_LEN];
- size_t datalen, var_name_len, var_val_len, maxlen;
- size_t sa_enterpriseoid_len;
- u_char vartype, *ptr, *var_val;
- long trap, specific;
- u_long timestamp;
- netsnmp_variable_list *snmptrap_head, *snmptrap_ptr, *snmptrap_tmp;
- snmptrap_head = NULL;
- snmptrap_ptr = NULL;
- ptr = rsp;
- /*
- * parse the sub-agent enterprise oid
- */
- sa_enterpriseoid_len = MAX_OID_LEN;
- if ((ptr = asn_parse_objid(ptr, len,
- &vartype, (oid *) & sa_enterpriseoid,
- &sa_enterpriseoid_len)) == NULL) {
- DEBUGMSGTL(("smux",
- "[smux_trap_process] asn_parse_objid failedn"));
- return NULL;
- }
- /*
- * parse the agent-addr ipAddress
- */
- datalen = SMUXMAXSTRLEN;
- if (((ptr = asn_parse_string(ptr, len,
- &vartype, smux_str,
- &datalen)) == NULL) ||
- (vartype != (u_char) ASN_IPADDRESS)) {
- DEBUGMSGTL(("smux",
- "[smux_trap_process] asn_parse_string failedn"));
- return NULL;
- }
- /*
- * parse the generic trap int
- */
- datalen = sizeof(long);
- if ((ptr = asn_parse_int(ptr, len, &vartype, &trap, datalen)) == NULL) {
- DEBUGMSGTL(("smux",
- "[smux_trap_process] asn_parse_int generic failedn"));
- return NULL;
- }
- /*
- * parse the specific trap int
- */
- datalen = sizeof(long);
- if ((ptr = asn_parse_int(ptr, len,
- &vartype, &specific, datalen)) == NULL) {
- DEBUGMSGTL(("smux",
- "[smux_trap_process] asn_parse_int specific failedn"));
- return NULL;
- }
- /*
- * parse the timeticks timestamp
- */
- datalen = sizeof(u_long);
- if (((ptr = asn_parse_unsigned_int(ptr, len,
- &vartype, (u_long *) & timestamp,
- datalen)) == NULL) ||
- (vartype != (u_char) ASN_TIMETICKS)) {
- DEBUGMSGTL(("smux",
- "[smux_trap_process] asn_parse_unsigned_int (timestamp) failedn"));
- return NULL;
- }
- /*
- * parse out the overall sequence
- */
- ptr = asn_parse_header(ptr, len, &vartype);
- if (ptr == NULL || vartype != (ASN_SEQUENCE | ASN_CONSTRUCTOR)) {
- return NULL;
- }
- /*
- * parse the variable bindings
- */
- while (ptr && *len) {
- /*
- * get the objid and the asn1 coded value
- */
- var_name_len = MAX_OID_LEN;
- ptr = snmp_parse_var_op(ptr, var_name, &var_name_len, &vartype,
- &var_val_len, (u_char **) & var_val, len);
- if (ptr == NULL) {
- return NULL;
- }
- maxlen = SMUXMAXPKTSIZE;
- switch ((short) vartype) {
- case ASN_INTEGER:
- var_val_len = sizeof(long);
- asn_parse_int(var_val, &maxlen, &vartype,
- (long *) &smux_long, var_val_len);
- var_val = (u_char *) & smux_long;
- break;
- case ASN_COUNTER:
- case ASN_GAUGE:
- case ASN_TIMETICKS:
- case ASN_UINTEGER:
- var_val_len = sizeof(u_long);
- asn_parse_unsigned_int(var_val, &maxlen, &vartype,
- (u_long *) & smux_ulong, var_val_len);
- var_val = (u_char *) & smux_ulong;
- break;
- case ASN_COUNTER64:
- var_val_len = sizeof(smux_counter64);
- asn_parse_unsigned_int64(var_val, &maxlen, &vartype,
- (struct counter64 *) &smux_counter64,
- var_val_len);
- var_val = (u_char *) & smux_counter64;
- break;
- case ASN_IPADDRESS:
- var_val_len = 4;
- /*
- * consume the tag and length, but just copy here
- * because we know it is an ip address
- */
- if ((var_val =
- asn_parse_header(var_val, &maxlen, &vartype)) == NULL)
- return NULL;
- memcpy((u_char *) & (smux_sa.sin_addr.s_addr), var_val,
- var_val_len);
- var_val = (u_char *) & (smux_sa.sin_addr.s_addr);
- break;
- case ASN_OPAQUE:
- case ASN_OCTET_STR:
- /*
- * XXX
- */
- if (len == 0)
- return NULL;
- var_val_len = SMUXMAXSTRLEN;
- asn_parse_string(var_val, &maxlen, &vartype,
- smux_str, &var_val_len);
- var_val = smux_str;
- break;
- case ASN_OBJECT_ID:
- var_val_len = MAX_OID_LEN;
- asn_parse_objid(var_val, &maxlen, &vartype,
- smux_objid, &var_val_len);
- var_val_len *= sizeof(oid);
- var_val = (u_char *) smux_objid;
- break;
- case SNMP_NOSUCHOBJECT:
- case SNMP_NOSUCHINSTANCE:
- case SNMP_ENDOFMIBVIEW:
- case ASN_NULL:
- var_val = NULL;
- break;
- case ASN_BIT_STR:
- /*
- * XXX
- */
- if (len == 0)
- return NULL;
- var_val_len = SMUXMAXSTRLEN;
- asn_parse_bitstring(var_val, &maxlen, &vartype,
- smux_str, &var_val_len);
- var_val = (u_char *) smux_str;
- break;
- case ASN_NSAP:
- default:
- snmp_log(LOG_ERR, "bad type returned (%x)n", vartype);
- var_val = NULL;
- break;
- }
- snmptrap_tmp =
- (netsnmp_variable_list *)
- malloc(sizeof(netsnmp_variable_list));
- if (snmptrap_tmp == NULL)
- return NULL;
- memset(snmptrap_tmp, 0, sizeof(netsnmp_variable_list));
- if (snmptrap_head == NULL) {
- snmptrap_head = snmptrap_tmp;
- snmptrap_ptr = snmptrap_head;
- } else {
- snmptrap_ptr->next_variable = snmptrap_tmp;
- snmptrap_ptr = snmptrap_ptr->next_variable;
- }
- snmp_set_var_objid(snmptrap_ptr, var_name, var_name_len);
- snmp_set_var_value(snmptrap_ptr, (char *) var_val, var_val_len);
- snmptrap_ptr->type = vartype;
- snmptrap_ptr->next_variable = NULL;
- }
- /*
- * send the traps
- */
- send_enterprise_trap_vars(trap, specific, (oid *) & sa_enterpriseoid,
- sa_enterpriseoid_len, snmptrap_head);
- /*
- * free trap variables
- */
- snmp_free_varbind(snmptrap_head);
- return ptr;
- }