0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki/*
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * CDDL HEADER START
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki *
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * The contents of this file are subject to the terms of the
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * Common Development and Distribution License (the "License").
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * You may not use this file except in compliance with the License.
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki *
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * or http://www.opensolaris.org/os/licensing.
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * See the License for the specific language governing permissions
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * and limitations under the License.
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki *
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * When distributing Covered Code, include this CDDL HEADER in each
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * If applicable, add the following below this CDDL HEADER, with the
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * fields enclosed by brackets "[]" replaced with your own identifying
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * information: Portions Copyright [yyyy] [name of copyright owner]
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki *
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * CDDL HEADER END
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki */
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki/*
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * Use is subject to license terms.
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki */
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki#pragma ident "%Z%%M% %I% %E% SMI"
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki/*
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * SNMP PDU and packet transport related routines
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki */
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki#include <stdio.h>
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki#include <stdlib.h>
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki#include <string.h>
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki#include <sys/types.h>
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki#include "asn1.h"
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki#include "pdu.h"
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki#include "debug.h"
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki/*
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * Static declarations
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki */
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenkistatic int snmp_add_null_vars(snmp_pdu_t *, char *, int, int);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenkistatic oid *snmp_oidstr_to_oid(int, char *, int, size_t *);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenkistatic uchar_t *snmp_build_pdu(snmp_pdu_t *, uchar_t *, size_t *);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenkistatic uchar_t *snmp_build_variable(uchar_t *, size_t *, oid *, size_t,
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki uchar_t, void *, size_t);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenkistatic uchar_t *snmp_parse_pdu(int, uchar_t *, size_t *, snmp_pdu_t *);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenkistatic uchar_t *snmp_parse_variable(uchar_t *, size_t *, pdu_varlist_t *);
4f90901ff7a0693b0be018de6dcfff7c6e11d734venkistatic void snmp_free_null_vars(pdu_varlist_t *);
4f90901ff7a0693b0be018de6dcfff7c6e11d734venki
4f90901ff7a0693b0be018de6dcfff7c6e11d734venkistatic uchar_t *snmp_def_community = (uchar_t *)SNMP_DEF_COMMUNITY;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki/*
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * Allocates and creates a PDU for the specified SNMP command. Currently
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * only SNMP_MSG_GET, SNMP_MSG_GETNEXT and SNMP_MSG_GETBULK are supported
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki */
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenkisnmp_pdu_t *
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenkisnmp_create_pdu(int cmd, int max_reps, char *oidstrs, int n_oids, int row)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki{
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki snmp_pdu_t *pdu;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if ((cmd != SNMP_MSG_GET) && (cmd != SNMP_MSG_GETNEXT) &&
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki (cmd != SNMP_MSG_GETBULK)) {
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return (NULL);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki }
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki pdu = (snmp_pdu_t *)calloc(1, sizeof (snmp_pdu_t));
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (pdu == NULL)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return (NULL);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (cmd == SNMP_MSG_GET || cmd == SNMP_MSG_GETNEXT) {
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki pdu->version = SNMP_VERSION_1;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki pdu->errstat = 0;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki pdu->errindex = 0;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki } else if (cmd == SNMP_MSG_GETBULK) {
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki pdu->version = SNMP_VERSION_2c;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki pdu->non_repeaters = 0;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki pdu->max_repetitions = max_reps ?
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki max_reps : SNMP_DEF_MAX_REPETITIONS;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki }
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki pdu->command = cmd;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki pdu->reqid = snmp_get_reqid();
4f90901ff7a0693b0be018de6dcfff7c6e11d734venki pdu->community = snmp_def_community;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki pdu->community_len = SNMP_DEF_COMMUNITY_LEN;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (snmp_add_null_vars(pdu, oidstrs, n_oids, row) < 0) {
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki free((void *) pdu);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return (NULL);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki }
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki pdu->req_pkt = NULL;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki pdu->req_pktsz = 0;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki pdu->reply_pkt = NULL;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki pdu->reply_pktsz = 0;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return (pdu);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki}
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki/*
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * Builds a complete ASN.1 encoded snmp message packet out of the PDU.
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * Currently the maximum request packet is limited to SNMP_DEF_PKTBUF_SZ.
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * Since we only send SNMP_MSG_GET, SNMP_MSG_GETNEXT and SNMP_MSG_GETBULK,
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * as long as the number of bulk oids are not *too* many, we're safe with
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * this limit (the typical packet size of a bulk request of 10 vars is
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * around 250 bytes).
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki */
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenkiint
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenkisnmp_make_packet(snmp_pdu_t *pdu)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki{
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki uchar_t *buf, *p;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki uchar_t *msg_seq_end;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki uchar_t id;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki size_t bufsz = SNMP_DEF_PKTBUF_SZ;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki size_t seqlen;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if ((buf = (uchar_t *)calloc(1, SNMP_DEF_PKTBUF_SZ)) == NULL)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return (-1);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki /*
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * Let's start with the ASN sequence tag. Set the length
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * to 0 initially and fill it up once the message packetizing
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * is complete.
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki */
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki id = ASN_UNIVERSAL | ASN_CONSTRUCTOR | ASN_SEQUENCE;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if ((p = asn_build_sequence(buf, &bufsz, id, 0)) == NULL) {
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki free((void *) buf);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return (-1);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki }
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki msg_seq_end = p;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki /*
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * Store the version
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki */
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki id = ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if ((p = asn_build_int(p, &bufsz, id, pdu->version)) == NULL) {
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki free((void *) buf);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return (-1);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki }
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki /*
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * Store the community string
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki */
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki id = ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki p = asn_build_string(p, &bufsz, id, pdu->community, pdu->community_len);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (p == NULL) {
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki free((void *) buf);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return (-1);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki }
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki /*
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * Build the PDU
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki */
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if ((p = snmp_build_pdu(pdu, p, &bufsz)) == NULL) {
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki free((void *) buf);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return (-1);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki }
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki /*
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * Complete the message pkt by updating the message sequence length
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki */
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki seqlen = p - msg_seq_end;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki id = ASN_UNIVERSAL | ASN_CONSTRUCTOR | ASN_SEQUENCE;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki (void) asn_build_sequence(buf, NULL, id, seqlen);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki /*
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * Calculate packet size and return
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki */
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki pdu->req_pkt = buf;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki pdu->req_pktsz = p - buf;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return (0);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki}
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki/*
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * Makes a PDU out of a reply packet. The reply message is parsed
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * and if the reqid of the incoming packet does not match the reqid
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * we're waiting for, an error is returned. The PDU is allocated
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * inside this routine and must be freed by the caller once it is no
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * longer needed.
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki */
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenkisnmp_pdu_t *
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenkisnmp_parse_reply(int reqid, uchar_t *reply_pkt, size_t reply_pktsz)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki{
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki snmp_pdu_t *reply_pdu;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki uchar_t *p;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki size_t msgsz = reply_pktsz;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki uchar_t exp_id;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki reply_pdu = (snmp_pdu_t *)calloc(1, sizeof (snmp_pdu_t));
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (reply_pdu == NULL)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return (NULL);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki /*
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * Try to parse the ASN sequence out of the beginning of the reply
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * packet. If we don't find a sequence at the beginning, something's
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * wrong.
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki */
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki exp_id = ASN_UNIVERSAL | ASN_CONSTRUCTOR | ASN_SEQUENCE;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if ((p = asn_parse_sequence(reply_pkt, &msgsz, exp_id)) == NULL) {
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki snmp_free_pdu(reply_pdu);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return (NULL);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki }
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki /*
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * Now try to parse the version out of the packet
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki */
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if ((p = asn_parse_int(p, &msgsz, &reply_pdu->version)) == NULL) {
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki snmp_free_pdu(reply_pdu);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return (NULL);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki }
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if ((reply_pdu->version != SNMP_VERSION_1) &&
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki (reply_pdu->version != SNMP_VERSION_2c)) {
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki snmp_free_pdu(reply_pdu);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return (NULL);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki }
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki /*
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * Parse the community string (space allocated by asn_parse_string)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki */
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki p = asn_parse_string(p, &msgsz, &reply_pdu->community,
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki &reply_pdu->community_len);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (p == NULL) {
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki snmp_free_pdu(reply_pdu);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return (NULL);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki }
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki /*
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * Parse the PDU part of the message
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki */
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if ((p = snmp_parse_pdu(reqid, p, &msgsz, reply_pdu)) == NULL) {
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki snmp_free_pdu(reply_pdu);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return (NULL);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki }
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return (reply_pdu);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki}
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki/*
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * Convert the OID strings into the standard PDU oid form (sequence of
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * integer subids) and add them to the PDU's variable list. Note that
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * this is used only for preparing the request messages (GET, GETNEXT
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * and GETBULK), so the values of the variables are always null.
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki */
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenkistatic int
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenkisnmp_add_null_vars(snmp_pdu_t *pdu, char *oidstrs, int n_oids, int row)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki{
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki pdu_varlist_t *vp, *prev;
4f90901ff7a0693b0be018de6dcfff7c6e11d734venki pdu_varlist_t *varblock_p = NULL;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki char *p;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki int i;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki prev = NULL;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki p = oidstrs;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki for (i = 0; i < n_oids; i++) {
4f90901ff7a0693b0be018de6dcfff7c6e11d734venki if ((vp = calloc(1, sizeof (pdu_varlist_t))) == NULL) {
4f90901ff7a0693b0be018de6dcfff7c6e11d734venki snmp_free_null_vars(varblock_p);
4f90901ff7a0693b0be018de6dcfff7c6e11d734venki return (-1);
4f90901ff7a0693b0be018de6dcfff7c6e11d734venki } else if (i == 0) {
4f90901ff7a0693b0be018de6dcfff7c6e11d734venki varblock_p = vp;
4f90901ff7a0693b0be018de6dcfff7c6e11d734venki } else {
4f90901ff7a0693b0be018de6dcfff7c6e11d734venki prev->nextvar = vp;
4f90901ff7a0693b0be018de6dcfff7c6e11d734venki }
4f90901ff7a0693b0be018de6dcfff7c6e11d734venki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki vp->name = snmp_oidstr_to_oid(pdu->command,
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki p, row, &vp->name_len);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (vp->name == NULL) {
4f90901ff7a0693b0be018de6dcfff7c6e11d734venki snmp_free_null_vars(varblock_p);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return (-1);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki }
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki vp->val.str = NULL;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki vp->val_len = 0;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki vp->type = ASN_NULL;
4f90901ff7a0693b0be018de6dcfff7c6e11d734venki vp->nextvar = NULL;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki LOGVAR(TAG_NULL_VAR, vp);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki prev = vp;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki p += strlen(p) + 1;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki }
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki /*
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * append the varlist to the PDU
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki */
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (pdu->vars == NULL)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki pdu->vars = varblock_p;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki else {
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki for (vp = pdu->vars; vp->nextvar; vp = vp->nextvar)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki ;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki vp->nextvar = varblock_p;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki }
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return (0);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki}
4f90901ff7a0693b0be018de6dcfff7c6e11d734venki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki/*
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * Some assumptions are in place here to eliminate unnecessary complexity.
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * All OID strings passed are assumed to be in the numeric string form, have
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * no leading/trailing '.' or spaces. Since PICL plugin is currently the
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * only customer, this is quite reasonable.
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki */
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenkistatic oid *
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenkisnmp_oidstr_to_oid(int cmd, char *oidstr, int row, size_t *n_subids)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki{
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki int i, count;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki char *p, *q;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki char *oidstr_dup;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki oid *objid;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if ((oidstr == NULL) || (n_subids == NULL))
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return (NULL);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki for (count = 1, p = oidstr; p; count++, p++) {
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if ((p = strchr(p, '.')) == NULL)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki break;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki }
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki /*
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * Add one more to count for 'row'. Need special processing
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * for SNMP_MSG_GETNEXT and SNMP_MSG_GETBULK requests; see
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * comment below.
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki */
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if ((cmd == SNMP_MSG_GET) || (cmd == SNMP_MSG_GETBULK && row > 0) ||
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki (cmd == SNMP_MSG_GETNEXT && row >= 0)) {
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki count++;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki }
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if ((oidstr_dup = strdup(oidstr)) == NULL)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return (NULL);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki objid = (oid *) calloc(count, sizeof (oid));
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (objid == NULL) {
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki free((void *) p);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return (NULL);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki }
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki p = oidstr_dup;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki for (i = 0; i < count - 1; i++) {
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (q = strchr(p, '.'))
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki *q = 0;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki objid[i] = (oid) strtoul(p, NULL, 10);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki p = q + 1;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki }
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki /*
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * For SNMP_MSG_GET, the leaf subid will simply be the row#.
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki *
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * For SNMP_MSG_GETBULK, if the row# passed is greater than 0,
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * we pass 'row-1' as the leaf subid, to include the item that
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * is of interest to us. If the row# is less than or equal to 0,
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * we will simply ignore it and pass only the prefix part of the
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * oidstr. For this case, our count would have been 1 less than
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * usual, and we are yet to save the last subid.
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki *
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * For SNMP_MSG_GETNEXT, if the row# passed is less than 0,
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * we'll simply ignore it and pass only the prefix part of the
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * oidstr. For this case, our count would have been 1 less than
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * usual, and we are yet to save the last subid. If the row#
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * passed is greater than or equal to 0, we'll simply pass it
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * verbatim, as the leaf subid.
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki */
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki switch (cmd) {
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki case SNMP_MSG_GET:
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki objid[i] = (oid) row;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki break;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki case SNMP_MSG_GETBULK:
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (row > 0)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki objid[i] = (oid) (row - 1);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki else
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki objid[i] = (oid) strtoul(p, NULL, 10);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki break;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki case SNMP_MSG_GETNEXT:
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (row < 0)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki objid[i] = (oid) strtoul(p, NULL, 10);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki else
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki objid[i] = (oid) row;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki break;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki }
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki *n_subids = count;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki free((void *) oidstr_dup);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return (objid);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki}
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki/*
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * Builds the PDU part of the snmp message packet.
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki */
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenkistatic uchar_t *
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenkisnmp_build_pdu(snmp_pdu_t *pdu, uchar_t *buf, size_t *bufsz_p)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki{
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki uchar_t *p;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki uchar_t *pdu_seq_begin, *pdu_seq_end;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki uchar_t *varlist_seq_begin, *varlist_seq_end;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki uchar_t id;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki size_t seqlen;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki pdu_varlist_t *vp;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki /*
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * Build ASN sequence for the PDU command (length will be
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * updated later once the entire command is completely formed)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki */
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki pdu_seq_begin = buf;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki p = asn_build_sequence(buf, bufsz_p, (uchar_t)pdu->command, 0);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (p == NULL)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return (NULL);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki pdu_seq_end = p;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki /*
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * Build the request id
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki */
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki id = ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if ((p = asn_build_int(p, bufsz_p, id, pdu->reqid)) == NULL)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return (NULL);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki /*
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * Build the non-repeaters and max-repetitions for SNMP_MSG_GETBULK
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * (same as error status and error index for other message types)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki */
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki id = ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if ((p = asn_build_int(p, bufsz_p, id, pdu->non_repeaters)) == NULL)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return (NULL);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki id = ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if ((p = asn_build_int(p, bufsz_p, id, pdu->max_repetitions)) == NULL)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return (NULL);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki /*
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * Build ASN sequence for the variables list (update length
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * after building the varlist)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki */
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki varlist_seq_begin = p;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki id = ASN_UNIVERSAL | ASN_CONSTRUCTOR | ASN_SEQUENCE;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if ((p = asn_build_sequence(p, bufsz_p, id, 0)) == NULL)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return (NULL);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki varlist_seq_end = p;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki /*
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * Build the variables list
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki */
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki for (vp = pdu->vars; vp; vp = vp->nextvar) {
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki p = snmp_build_variable(p, bufsz_p, vp->name, vp->name_len,
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki vp->type, vp->val.str, vp->val_len);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (p == NULL)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return (NULL);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki }
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki /*
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * Now update the varlist sequence length
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki */
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki seqlen = p - varlist_seq_end;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki id = ASN_UNIVERSAL | ASN_CONSTRUCTOR | ASN_SEQUENCE;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki (void) asn_build_sequence(varlist_seq_begin, NULL, id, seqlen);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki /*
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * And finally, update the length for the PDU sequence
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki */
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki seqlen = p - pdu_seq_end;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki (void) asn_build_sequence(pdu_seq_begin, NULL, (uchar_t)pdu->command,
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki seqlen);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return (p);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki}
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki/*
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * Builds an object variable into the snmp message packet. Although the
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * code is here to build variables of basic types such as integer, object id
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * and strings, the only type of variable we ever send via snmp request
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * messages is the ASN_NULL type.
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki */
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenkistatic uchar_t *
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenkisnmp_build_variable(uchar_t *buf, size_t *bufsz_p, oid *name, size_t name_len,
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki uchar_t val_type, void *val, size_t val_len)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki{
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki uchar_t *p, *varseq_end;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki size_t seqlen;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki uchar_t id;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki /*
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * Each variable binding is in turn defined as a 'SEQUENCE of' by
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * the SNMP PDU format, so we'll prepare the sequence and fill up
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * the length later. Sigh!
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki */
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki id = ASN_UNIVERSAL | ASN_CONSTRUCTOR | ASN_SEQUENCE;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if ((p = asn_build_sequence(buf, bufsz_p, id, 0)) == NULL)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return (NULL);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki varseq_end = p;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki /*
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * Build the object id
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki */
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki id = ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if ((p = asn_build_objid(p, bufsz_p, id, name, name_len)) == NULL)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return (NULL);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki /*
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * Currently we only ever build ASN_NULL vars while sending requests,
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * since we support only SNMP_MSG_GET, SNMP_MSG_GETNEXT and
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * SNMP_MSG_GETBULK.
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki */
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki id = ASN_UNIVERSAL | ASN_PRIMITIVE | val_type;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki switch (val_type) {
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki case ASN_INTEGER:
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki p = asn_build_int(p, bufsz_p, id, *((int *)val));
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (p == NULL)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return (NULL);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki break;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki case ASN_OBJECT_ID:
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki p = asn_build_objid(p, bufsz_p, id, val,
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki val_len / sizeof (oid));
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (p == NULL)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return (NULL);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki break;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki case ASN_OCTET_STR:
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki p = asn_build_string(p, bufsz_p, id, (uchar_t *)val, val_len);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (p == NULL)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return (NULL);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki break;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki case ASN_NULL:
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if ((p = asn_build_null(p, bufsz_p, id)) == NULL)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return (NULL);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki break;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki default:
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return (NULL);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki }
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki /*
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * Rebuild the variable sequence length
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki */
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki seqlen = p - varseq_end;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki id = ASN_UNIVERSAL | ASN_CONSTRUCTOR | ASN_SEQUENCE;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki (void) asn_build_sequence(buf, NULL, id, seqlen);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return (p);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki}
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki/*
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * Parse the PDU portion of the incoming snmp message into the reply_pdu.
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * Space for all structure members are allocated as needed and must be freed
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * by the caller when these are no longer needed.
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki */
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenkistatic uchar_t *
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenkisnmp_parse_pdu(int reqid, uchar_t *msg, size_t *msgsz_p, snmp_pdu_t *reply_pdu)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki{
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki uchar_t *p;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki uchar_t id, exp_id;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki pdu_varlist_t *newvp, *vp = NULL;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki /*
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * Parse the PDU header out of the message
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki */
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if ((p = asn_parse_header(msg, msgsz_p, &id)) == NULL)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return (NULL);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (id != SNMP_MSG_RESPONSE && id != SNMP_MSG_REPORT)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return (NULL);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki reply_pdu->command = (int)id;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki /*
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * Parse the request id and verify that this is the response
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * we're expecting.
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki */
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if ((p = asn_parse_int(p, msgsz_p, &reply_pdu->reqid)) == NULL)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return (NULL);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (reply_pdu->reqid != reqid)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return (NULL);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki /*
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * Parse the error-status and error-index values
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki */
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if ((p = asn_parse_int(p, msgsz_p, &reply_pdu->errstat)) == NULL)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return (NULL);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if ((p = asn_parse_int(p, msgsz_p, &reply_pdu->errindex)) == NULL)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return (NULL);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki /*
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * Parse the header for the variables list sequence.
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki */
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki exp_id = ASN_UNIVERSAL | ASN_CONSTRUCTOR | ASN_SEQUENCE;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if ((p = asn_parse_sequence(p, msgsz_p, exp_id)) == NULL)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return (NULL);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki while (((int)*msgsz_p) > 0) {
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if ((newvp = calloc(1, sizeof (pdu_varlist_t))) == NULL)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return (NULL);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (vp == NULL)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki reply_pdu->vars = newvp;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki else
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki vp->nextvar = newvp;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki vp = newvp;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if ((p = snmp_parse_variable(p, msgsz_p, vp)) == NULL)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return (NULL);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki LOGVAR(TAG_RESPONSE_VAR, vp);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki }
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return (p);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki}
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki/*
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * Allocate and parse the next variable into the varlist
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki */
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenkistatic uchar_t *
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenkisnmp_parse_variable(uchar_t *msg, size_t *msgsz_p, pdu_varlist_t *vp)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki{
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki uchar_t *p;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki uchar_t exp_id;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki /*
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * Parse this variable's sequence
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki */
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki exp_id = ASN_UNIVERSAL | ASN_CONSTRUCTOR | ASN_SEQUENCE;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if ((p = asn_parse_sequence(msg, msgsz_p, exp_id)) == NULL)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return (NULL);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki /*
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * Parse the variable's object identifier
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki */
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki p = asn_parse_objid(p, msgsz_p, &vp->name, &vp->name_len);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (p == NULL)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return (NULL);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki /*
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki * Parse the object's value
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki */
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if ((p = asn_parse_objval(p, msgsz_p, vp)) == NULL)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return (NULL);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return (p);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki}
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenkivoid
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenkisnmp_free_pdu(snmp_pdu_t *pdu)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki{
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki pdu_varlist_t *vp, *nxt;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (pdu) {
4f90901ff7a0693b0be018de6dcfff7c6e11d734venki if ((pdu->community) && (pdu->community != snmp_def_community))
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki free((void *) pdu->community);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki for (vp = pdu->vars; vp; vp = nxt) {
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki nxt = vp->nextvar;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (vp->name)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki free((void *) vp->name);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (vp->val.str)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki free((void *) vp->val.str);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki free((void *) vp);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki }
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (pdu->req_pkt)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki free((void *) pdu->req_pkt);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (pdu->reply_pkt)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki free((void *) pdu->reply_pkt);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki free((void *) pdu);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki }
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki}
4f90901ff7a0693b0be018de6dcfff7c6e11d734venki
4f90901ff7a0693b0be018de6dcfff7c6e11d734venkistatic void
4f90901ff7a0693b0be018de6dcfff7c6e11d734venkisnmp_free_null_vars(pdu_varlist_t *varblock_p)
4f90901ff7a0693b0be018de6dcfff7c6e11d734venki{
4f90901ff7a0693b0be018de6dcfff7c6e11d734venki pdu_varlist_t *vp, *nxt;
4f90901ff7a0693b0be018de6dcfff7c6e11d734venki
4f90901ff7a0693b0be018de6dcfff7c6e11d734venki for (vp = varblock_p; vp; vp = nxt) {
4f90901ff7a0693b0be018de6dcfff7c6e11d734venki nxt = vp->nextvar;
4f90901ff7a0693b0be018de6dcfff7c6e11d734venki
4f90901ff7a0693b0be018de6dcfff7c6e11d734venki if (vp->name)
4f90901ff7a0693b0be018de6dcfff7c6e11d734venki free(vp->name);
4f90901ff7a0693b0be018de6dcfff7c6e11d734venki free(vp);
4f90901ff7a0693b0be018de6dcfff7c6e11d734venki }
4f90901ff7a0693b0be018de6dcfff7c6e11d734venki}