Path: blob/main/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptc.c
106842 views
/*-1* Copyright (c) 2006 The FreeBSD Project2* All rights reserved.3*4* Author: Shteryana Shopova <[email protected]>5*6* Redistribution of this software and documentation and use in source and7* binary forms, with or without modification, are permitted provided that8* the following conditions are met:9*10* 1. Redistributions of source code or documentation must retain the above11* copyright notice, this list of conditions and the following disclaimer.12* 2. Redistributions in binary form must reproduce the above copyright13* notice, this list of conditions and the following disclaimer in the14* documentation and/or other materials provided with the distribution.15*16* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND17* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE18* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE19* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE20* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL21* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS22* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)23* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT24* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY25* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF26* SUCH DAMAGE.27*28* Textual conventions for OctetStrings29*/3031#include <sys/param.h>32#include <sys/queue.h>33#include <sys/socket.h>34#include <sys/uio.h>3536#include <ctype.h>37#include <err.h>38#include <errno.h>39#include <fcntl.h>40#include <stdio.h>41#include <stdlib.h>42#include <string.h>43#include <syslog.h>44#include <unistd.h>4546#include <arpa/inet.h>47#include <netinet/in.h>4849#include <bsnmp/asn1.h>50#include <bsnmp/snmp.h>51#include "bsnmptc.h"52#include "bsnmptools.h"5354/* OctetString, DisplayString */55static char *snmp_oct2str(uint32_t, char *, char *);56static char *snmp_str2asn_oid(char *, struct asn_oid *);57static int parse_octetstring(struct snmp_value *, char *);5859/* DateAndTime */60static char *snmp_octstr2date(uint32_t, char *, char *);61static char *snmp_date2asn_oid(char * , struct asn_oid *);62static int parse_dateandtime(struct snmp_value *, char *);6364/* PhysAddress */65static char *snmp_oct2physAddr(uint32_t, char *, char *);66static char *snmp_addr2asn_oid(char *, struct asn_oid *);67static int parse_physaddress(struct snmp_value *, char *);6869/* NTPTimeStamp */70static char *snmp_oct2ntp_ts(uint32_t, char *, char *);71static char *snmp_ntp_ts2asn_oid(char *, struct asn_oid *);72static int parse_ntp_ts(struct snmp_value *, char *);7374/* BridgeId */75static char *snmp_oct2bridgeid(uint32_t, char *, char *);76static char *snmp_bridgeid2oct(char *, struct asn_oid *);77static int parse_bridge_id(struct snmp_value *, char *);7879/* BridgePortId */80static char *snmp_oct2bport_id(uint32_t, char *, char *);81static char *snmp_bport_id2oct(char *, struct asn_oid *);82static int parse_bport_id(struct snmp_value *, char *);8384/* InetAddress */85static char *snmp_oct2inetaddr(uint32_t len, char *octets, char *buf);86static char *snmp_inetaddr2oct(char *str, struct asn_oid *oid);87static int32_t parse_inetaddr(struct snmp_value *value, char *string);8889static char *snmp_oct2bits(uint32_t len, char *octets, char *buf);90static char *snmp_bits2oct(char *str, struct asn_oid *oid);91static int32_t parse_bits(struct snmp_value *value, char *string);9293static struct snmp_text_conv {94enum snmp_tc tc;95const char *tc_str;96int32_t len;97snmp_oct2tc_f oct2tc;98snmp_tc2oid_f tc2oid;99snmp_tc2oct_f tc2oct;100} text_convs[] = {101{ SNMP_STRING, "OctetString", SNMP_VAR_STRSZ,102snmp_oct2str, snmp_str2asn_oid, parse_octetstring },103104{ SNMP_DISPLAYSTRING, "DisplayString" , SNMP_VAR_STRSZ,105snmp_oct2str, snmp_str2asn_oid, parse_octetstring },106107{ SNMP_DATEANDTIME, "DateAndTime", SNMP_DATETIME_STRSZ,108snmp_octstr2date, snmp_date2asn_oid, parse_dateandtime },109110{ SNMP_PHYSADDR, "PhysAddress", SNMP_PHYSADDR_STRSZ,111snmp_oct2physAddr, snmp_addr2asn_oid, parse_physaddress },112113{ SNMP_ATMESI, "AtmESI", SNMP_PHYSADDR_STRSZ,114snmp_oct2physAddr, snmp_addr2asn_oid, parse_physaddress },115116{ SNMP_NTP_TIMESTAMP, "NTPTimeStamp", SNMP_NTP_TS_STRSZ,117snmp_oct2ntp_ts, snmp_ntp_ts2asn_oid, parse_ntp_ts },118119{ SNMP_MACADDRESS, "MacAddress", SNMP_PHYSADDR_STRSZ,120snmp_oct2physAddr, snmp_addr2asn_oid, parse_physaddress },121122{ SNMP_BRIDGE_ID, "BridgeId", SNMP_BRIDGEID_STRSZ,123snmp_oct2bridgeid, snmp_bridgeid2oct, parse_bridge_id },124125{ SNMP_BPORT_ID, "BridgePortId", SNMP_BPORT_STRSZ,126snmp_oct2bport_id, snmp_bport_id2oct, parse_bport_id },127128{ SNMP_INETADDRESS, "InetAddress", SNMP_INADDRS_STRSZ,129snmp_oct2inetaddr, snmp_inetaddr2oct, parse_inetaddr },130131{ SNMP_TC_OWN, "BITS", SNMP_VAR_STRSZ,132snmp_oct2bits, snmp_bits2oct, parse_bits },133134{ SNMP_UNKNOWN, "Unknown", SNMP_VAR_STRSZ, snmp_oct2str,135snmp_str2asn_oid, parse_octetstring } /* keep last */136};137138/* Common API */139enum snmp_tc140snmp_get_tc(char *str)141{142int i;143for (i = 0; i < SNMP_UNKNOWN; i++) {144if (!strncmp(text_convs[i].tc_str, str,145strlen(text_convs[i].tc_str)))146return (text_convs[i].tc);147}148149return (SNMP_STRING);150}151152char *153snmp_oct2tc(enum snmp_tc tc, uint32_t len, char *octets)154{155uint32_t tc_len;156char * buf;157158if (tc > SNMP_UNKNOWN)159tc = SNMP_UNKNOWN;160161if (text_convs[tc].len > 0)162tc_len = text_convs[tc].len;163else164tc_len = 2 * len + 3;165166if ((buf = malloc(tc_len)) == NULL ) {167syslog(LOG_ERR, "malloc failed - %s", strerror(errno));168return (NULL);169}170171memset(buf, 0, tc_len);172if (text_convs[tc].oct2tc(len, octets, buf) == NULL) {173free(buf);174return (NULL);175}176177return (buf);178}179180char *181snmp_tc2oid(enum snmp_tc tc, char *str, struct asn_oid *oid)182{183if (tc > SNMP_UNKNOWN)184tc = SNMP_UNKNOWN;185186return (text_convs[tc].tc2oid(str, oid));187}188189int32_t190snmp_tc2oct(enum snmp_tc tc, struct snmp_value *value, char *string)191{192if (tc > SNMP_UNKNOWN)193tc = SNMP_UNKNOWN;194195return (text_convs[tc].tc2oct(value, string));196}197198/*****************************************************199* Basic OctetString type.200*/201static char *202snmp_oct2str(uint32_t len, char *octets, char *buf)203{204uint8_t binary = 0;205uint32_t i;206char *ptr;207208if (len > MAX_OCTSTRING_LEN || octets == NULL || buf == NULL)209return (NULL);210211for (ptr = buf, i = 0; i < len; i++)212if (!isprint(octets[i])) {213binary = 1;214buf += sprintf(buf, "0x");215break;216}217218for (ptr = buf, i = 0; i < len; i++)219if (!binary)220ptr += sprintf(ptr, "%c", octets[i]);221else222ptr += sprintf(ptr, "%2.2x", (u_char)octets[i]);223224return (buf);225}226227static char *228snmp_str2asn_oid(char *str, struct asn_oid *oid)229{230uint32_t i, len = 0;231232/*233* OctetStrings are allowed max length of ASN_MAXOCTETSTRING,234* but trying to index an entry with such a long OctetString235* will fail anyway.236*/237for (len = 0; len < ASN_MAXOIDLEN; len++) {238if (strchr(",]", *(str + len)) != NULL)239break;240}241242if (len >= ASN_MAXOIDLEN)243return (NULL);244245if (snmp_suboid_append(oid, (asn_subid_t) len) < 0)246return (NULL);247248for (i = 0; i < len; i++)249if (snmp_suboid_append(oid, (asn_subid_t) *(str + i)) < 0)250return (NULL);251252return (str + len);253}254255static int32_t256parse_octetstring(struct snmp_value *value, char *val)257{258size_t len;259260if ((len = strlen(val)) >= MAX_OCTSTRING_LEN) {261warnx("Octetstring too long - %d is max allowed",262MAX_OCTSTRING_LEN - 1);263return (-1);264}265266if ((value->v.octetstring.octets = malloc(len)) == NULL) {267value->v.octetstring.len = 0;268syslog(LOG_ERR, "malloc failed: %s", strerror(errno));269return (-1);270}271272value->v.octetstring.len = len;273memcpy(value->v.octetstring.octets, val, len);274value->syntax = SNMP_SYNTAX_OCTETSTRING;275276return (0);277}278279/*************************************************************280* DateAndTime281*************************************************************282* rfc 2579 specification:283* DateAndTime ::= TEXTUAL-CONVENTION284* DISPLAY-HINT "2d-1d-1d,1d:1d:1d.1d,1a1d:1d"285* STATUS current286* DESCRIPTION287* "A date-time specification.288*289* field octets contents range290* ----- ------ -------- -----291* 1 1-2 year* 0..65536292* 2 3 month 1..12293* 3 4 day 1..31294* 4 5 hour 0..23295* 5 6 minutes 0..59296* 6 7 seconds 0..60297* (use 60 for leap-second)298* 7 8 deci-seconds 0..9299* 8 9 direction from UTC '+' / '-'300* 9 10 hours from UTC* 0..13301* 10 11 minutes from UTC 0..59302*303* * Notes:304* - the value of year is in network-byte order305* - daylight saving time in New Zealand is +13306*307* For example, Tuesday May 26, 1992 at 1:30:15 PM EDT would be308* displayed as:309*310* 1992-5-26,13:30:15.0,-4:0311*/312static char *313snmp_octstr2date(uint32_t len, char *octets, char *buf)314{315int year;316char *ptr;317318if (len != SNMP_DATETIME_OCTETS || octets == NULL || buf == NULL)319return (NULL);320321buf[0]= '\0';322year = (octets[0] << 8);323year += (octets[1]);324325ptr = buf;326ptr += sprintf(ptr, "%4.4d-%.2d-%.2d, ", year, octets[2],octets[3]);327ptr += sprintf(ptr, "%2.2d:%2.2d:%2.2d.%.2d, ", octets[4],octets[5],328octets[6],octets[7]);329ptr += sprintf(ptr, "%c%.2d:%.2d", octets[8],octets[9],octets[10]);330331return (buf);332}333334static char *335snmp_date2asn_oid(char *str, struct asn_oid *oid)336{337char *endptr, *ptr;338static const char UTC[3] __nonstring = "UTC";339int32_t saved_errno;340uint32_t v;341342if (snmp_suboid_append(oid, (asn_subid_t) SNMP_DATETIME_OCTETS) < 0)343return (NULL);344345/* Read 'YYYY-' and write it in two subs. */346ptr = str;347saved_errno = errno;348errno = 0;349v = strtoul(ptr, &endptr, 10);350if (v > 0xffff)351goto error;352else353errno = saved_errno;354if (*endptr != '-')355goto error1;356if (snmp_suboid_append(oid, (asn_subid_t) ((v & 0xff00) >> 8)) < 0)357return (NULL);358if (snmp_suboid_append(oid, (asn_subid_t) (v & 0xff)) < 0)359return (NULL);360361/* 'MM-' */362ptr = endptr + 1;363saved_errno = errno;364errno = 0;365v = strtoul(ptr, &endptr, 10);366if (errno != 0)367goto error;368else369errno = saved_errno;370if (*endptr != '-')371goto error1;372if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)373return (NULL);374375/* 'DD,' */376ptr = endptr + 1;377saved_errno = errno;378errno = 0;379v = strtoul(ptr, &endptr, 10);380if (errno != 0)381goto error;382else383errno = saved_errno;384if (*endptr != '-')385goto error1;386if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)387return (NULL);388389/* 'HH:' */390ptr = endptr + 1;391saved_errno = errno;392errno = 0;393v = strtoul(ptr, &endptr, 10);394if (errno != 0)395goto error;396else397errno = saved_errno;398if (*endptr != ':')399goto error1;400if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)401return (NULL);402403/* 'MM:' */404ptr = endptr + 1;405saved_errno = errno;406errno = 0;407v = strtoul(ptr, &endptr, 10);408if (errno != 0)409goto error;410else411errno = saved_errno;412if (*endptr != ':')413goto error1;414if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)415return (NULL);416417/* 'SS.' */418ptr = endptr + 1;419saved_errno = errno;420errno = 0;421v = strtoul(ptr, &endptr, 10);422if (errno != 0)423goto error;424else425errno = saved_errno;426if (*endptr != '.')427goto error1;428if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)429return (NULL);430431/* 'M(mseconds),' */432ptr = endptr + 1;433saved_errno = errno;434errno = 0;435v = strtoul(ptr, &endptr, 10);436if (errno != 0)437goto error;438else439errno = saved_errno;440if (*endptr != ',')441goto error1;442if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)443return (NULL);444445/* 'UTC' - optional */446ptr = endptr + 1;447if (strncmp(ptr, UTC, sizeof(UTC)) == 0)448ptr += sizeof(UTC);449450/* '+/-' */451if (*ptr == '-' || *ptr == '+') {452if (snmp_suboid_append(oid, (asn_subid_t) (*ptr)) < 0)453return (NULL);454} else455goto error1;456457/* 'HH:' */458ptr = endptr + 1;459saved_errno = errno;460errno = 0;461v = strtoul(ptr, &endptr, 10);462if (errno != 0)463goto error;464else465errno = saved_errno;466if (*endptr != ':')467goto error1;468if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)469return (NULL);470471/* 'MM' - last one - ignore endptr here. */472ptr = endptr + 1;473saved_errno = errno;474errno = 0;475v = strtoul(ptr, &endptr, 10);476if (errno != 0)477goto error;478else479errno = saved_errno;480if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)481return (NULL);482483return (endptr);484485error:486errno = saved_errno;487error1:488warnx("Date value %s not supported", str);489return (NULL);490}491492/* Read a DateAndTime string eg. 1992-5-26,13:30:15.0,-4:0. */493static int32_t494parse_dateandtime(struct snmp_value *sv, char *val)495{496char *endptr;497uint32_t v;498uint8_t date[SNMP_DATETIME_OCTETS];499500/* 'YYYY-' */501v = strtoul(val, &endptr, 10);502if (v > 0xffff || *endptr != '-')503goto error;504date[0] = ((v & 0xff00) >> 8);505date[1] = (v & 0xff);506val = endptr + 1;507508/* 'MM-' */509v = strtoul(val, &endptr, 10);510if (v == 0 || v > 12 || *endptr != '-')511goto error;512date[2] = v;513val = endptr + 1;514515/* 'DD,' */516v = strtoul(val, &endptr, 10);517if (v == 0 || v > 31 || *endptr != ',')518goto error;519date[3] = v;520val = endptr + 1;521522/* 'HH:' */523v = strtoul(val, &endptr, 10);524if (v > 23 || *endptr != ':')525goto error;526date[4] = v;527val = endptr + 1;528529/* 'MM:' */530v = strtoul(val, &endptr, 10);531if (v > 59 || *endptr != ':')532goto error;533date[5] = v;534val = endptr + 1;535536/* 'SS.' */537v = strtoul(val, &endptr, 10);538if (v > 60 || *endptr != '.')539goto error;540date[6] = v;541val = endptr + 1;542543/* '(deci-)s,' */544v = strtoul(val, &endptr, 10);545if (v > 9 || *endptr != ',')546goto error;547date[7] = v;548val = endptr + 1;549550/* offset - '+/-' */551if (*val != '-' && *val != '+')552goto error;553date[8] = (uint8_t) *val;554val = endptr + 1;555556/* 'HH:' - offset from UTC */557v = strtoul(val, &endptr, 10);558if (v > 13 || *endptr != ':')559goto error;560date[9] = v;561val = endptr + 1;562563/* 'MM'\0'' offset from UTC */564v = strtoul(val, &endptr, 10);565if (v > 59 || *endptr != '\0')566goto error;567date[10] = v;568569if ((sv->v.octetstring.octets = malloc(SNMP_DATETIME_OCTETS)) == NULL) {570warn("malloc() failed");571return (-1);572}573574sv->v.octetstring.len = SNMP_DATETIME_OCTETS;575memcpy(sv->v.octetstring.octets, date, SNMP_DATETIME_OCTETS);576sv->syntax = SNMP_SYNTAX_OCTETSTRING;577return (1);578579error:580warnx("Date value %s not supported", val);581return (-1);582}583584/**************************************************************585* PhysAddress586*/587static char *588snmp_oct2physAddr(uint32_t len, char *octets, char *buf)589{590char *ptr;591uint32_t i;592593if (len != SNMP_PHYSADDR_OCTETS || octets == NULL || buf == NULL)594return (NULL);595596buf[0]= '\0';597598ptr = buf;599ptr += sprintf(ptr, "%2.2x", octets[0]);600for (i = 1; i < 6; i++)601ptr += sprintf(ptr, ":%2.2x", octets[i]);602603return (buf);604}605606static char *607snmp_addr2asn_oid(char *str, struct asn_oid *oid)608{609char *endptr, *ptr;610uint32_t v, i;611int saved_errno;612613if (snmp_suboid_append(oid, (asn_subid_t) SNMP_PHYSADDR_OCTETS) < 0)614return (NULL);615616ptr = str;617for (i = 0; i < 5; i++) {618saved_errno = errno;619v = strtoul(ptr, &endptr, 16);620errno = saved_errno;621if (v > 0xff) {622warnx("Integer value %s not supported", str);623return (NULL);624}625if (*endptr != ':') {626warnx("Failed adding oid - %s", str);627return (NULL);628}629if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)630return (NULL);631ptr = endptr + 1;632}633634/* The last one - don't check the ending char here. */635saved_errno = errno;636v = strtoul(ptr, &endptr, 16);637errno = saved_errno;638if (v > 0xff) {639warnx("Integer value %s not supported", str);640return (NULL);641}642if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)643return (NULL);644645return (endptr);646}647648static int32_t649parse_physaddress(struct snmp_value *sv, char *val)650{651char *endptr;652int32_t i;653uint32_t v;654uint8_t phys_addr[SNMP_PHYSADDR_OCTETS];655656for (i = 0; i < 5; i++) {657v = strtoul(val, &endptr, 16);658if (v > 0xff) {659warnx("Integer value %s not supported", val);660return (-1);661}662if(*endptr != ':') {663warnx("Failed reading octet - %s", val);664return (-1);665}666phys_addr[i] = v;667val = endptr + 1;668}669670/* The last one - don't check the ending char here. */671v = strtoul(val, &endptr, 16);672if (v > 0xff) {673warnx("Integer value %s not supported", val);674return (-1);675}676phys_addr[5] = v;677678if ((sv->v.octetstring.octets = malloc(SNMP_PHYSADDR_OCTETS)) == NULL) {679syslog(LOG_ERR, "malloc failed: %s", strerror(errno));680return (-1);681}682683sv->v.octetstring.len = SNMP_PHYSADDR_OCTETS;684memcpy(sv->v.octetstring.octets, phys_addr, SNMP_PHYSADDR_OCTETS);685sv->syntax = SNMP_SYNTAX_OCTETSTRING;686return (1);687}688689/**************************************************************690* NTPTimeStamp691**************************************************************692* NTP MIB, Revision 0.2, 7/25/97:693* NTPTimeStamp ::= TEXTUAL-CONVENTION694* DISPLAY-HINT "4x.4x"695* STATUS current696* DESCRIPTION697* ""698* SYNTAX OCTET STRING (SIZE(8))699*/700static char *701snmp_oct2ntp_ts(uint32_t len, char *octets, char *buf)702{703char *ptr;704uint32_t i;705706if (len != SNMP_NTP_TS_OCTETS || octets == NULL || buf == NULL)707return (NULL);708709buf[0]= '\0';710711ptr = buf;712i = octets[0] * 1000 + octets[1] * 100 + octets[2] * 10 + octets[3];713ptr += sprintf(ptr, "%4.4d", i);714i = octets[4] * 1000 + octets[5] * 100 + octets[6] * 10 + octets[7];715ptr += sprintf(ptr, ".%4.4d", i);716717return (buf);718}719720static char *721snmp_ntp_ts2asn_oid(char *str, struct asn_oid *oid)722{723char *endptr, *ptr;724uint32_t v, i, d;725struct asn_oid suboid;726int saved_errno;727728if (snmp_suboid_append(oid, (asn_subid_t) SNMP_NTP_TS_OCTETS) < 0)729return (NULL);730731ptr = str;732saved_errno = errno;733errno = 0;734v = strtoul(ptr, &endptr, 10);735if (errno != 0 || (v / 1000) > 9) {736warnx("Integer value %s not supported", str);737errno = saved_errno;738return (NULL);739} else740errno = saved_errno;741742if (*endptr != '.') {743warnx("Failed adding oid - %s", str);744return (NULL);745}746747memset(&suboid, 0, sizeof(struct asn_oid));748suboid.len = SNMP_NTP_TS_OCTETS;749750for (i = 0, d = 1000; i < 4; i++) {751suboid.subs[i] = v / d;752v = v % d;753d = d / 10;754}755756ptr = endptr + 1;757saved_errno = errno;758errno = 0;759v = strtoul(ptr, &endptr, 10);760if (errno != 0 || (v / 1000) > 9) {761warnx("Integer value %s not supported", str);762errno = saved_errno;763return (NULL);764} else765errno = saved_errno;766767for (i = 0, d = 1000; i < 4; i++) {768suboid.subs[i + 4] = v / d;769v = v % d;770d = d / 10;771}772773asn_append_oid(oid, &suboid);774return (endptr);775}776777static int32_t778parse_ntp_ts(struct snmp_value *sv, char *val)779{780char *endptr;781int32_t i, d, saved_errno;782uint32_t v;783uint8_t ntp_ts[SNMP_NTP_TS_OCTETS];784785saved_errno = errno;786errno = 0;787v = strtoul(val, &endptr, 10);788if (errno != 0 || (v / 1000) > 9) {789errno = saved_errno;790warnx("Integer value %s not supported", val);791return (-1);792} else793errno = saved_errno;794795if (*endptr != '.') {796warnx("Failed reading octet - %s", val);797return (-1);798}799800for (i = 0, d = 1000; i < 4; i++) {801ntp_ts[i] = v / d;802v = v % d;803d = d / 10;804}805val = endptr + 1;806807saved_errno = errno;808errno = 0;809v = strtoul(val, &endptr, 10);810if (errno != 0 || (v / 1000) > 9) {811errno = saved_errno;812warnx("Integer value %s not supported", val);813return (-1);814} else815errno = saved_errno;816817for (i = 0, d = 1000; i < 4; i++) {818ntp_ts[i + 4] = v / d;819v = v % d;820d = d / 10;821}822823if ((sv->v.octetstring.octets = malloc(SNMP_NTP_TS_OCTETS)) == NULL) {824syslog(LOG_ERR, "malloc failed: %s", strerror(errno));825return (-1);826}827828sv->v.octetstring.len = SNMP_NTP_TS_OCTETS;829memcpy(sv->v.octetstring.octets, ntp_ts, SNMP_NTP_TS_OCTETS);830sv->syntax = SNMP_SYNTAX_OCTETSTRING;831return (1);832}833834/**************************************************************835* BridgeId836**************************************************************837* BRIDGE-MIB, REVISION "200509190000Z"838* BridgeId ::= TEXTUAL-CONVENTION839* STATUS current840* DESCRIPTION841* "The Bridge-Identifier, as used in the Spanning Tree842* Protocol, to uniquely identify a bridge. Its first two843* octets (in network byte order) contain a priority value,844* and its last 6 octets contain the MAC address used to845* refer to a bridge in a unique fashion (typically, the846* numerically smallest MAC address of all ports on the847* bridge)."848* SYNTAX OCTET STRING (SIZE (8))849*/850static char *851snmp_oct2bridgeid(uint32_t len, char *octets, char *buf)852{853char *ptr;854uint32_t i, priority;855856if (len != SNMP_BRIDGEID_OCTETS || octets == NULL || buf == NULL)857return (NULL);858859buf[0]= '\0';860ptr = buf;861862priority = octets[0] << 8;863priority += octets[1];864if (priority > SNMP_MAX_BRIDGE_PRIORITY) {865warnx("Invalid bridge priority %d", priority);866return (NULL);867} else868ptr += sprintf(ptr, "%d.", octets[0]);869870ptr += sprintf(ptr, "%2.2x", octets[2]);871872for (i = 1; i < 6; i++)873ptr += sprintf(ptr, ":%2.2x", octets[i + 2]);874875return (buf);876}877878static char *879snmp_bridgeid2oct(char *str, struct asn_oid *oid)880{881char *endptr, *ptr;882uint32_t v, i;883int32_t saved_errno;884885if (snmp_suboid_append(oid, (asn_subid_t) SNMP_BRIDGEID_OCTETS) < 0)886return (NULL);887888ptr = str;889/* Read the priority. */890saved_errno = errno;891errno = 0;892v = strtoul(ptr, &endptr, 10);893894if (v > SNMP_MAX_BRIDGE_PRIORITY || errno != 0 || *endptr != '.') {895errno = saved_errno;896warnx("Bad bridge priority value %d", v);897return (NULL);898}899900if (snmp_suboid_append(oid, (asn_subid_t) (v & 0xff00)) < 0)901return (NULL);902903if (snmp_suboid_append(oid, (asn_subid_t) (v & 0xff)) < 0)904return (NULL);905906ptr = endptr + 1;907for (i = 0; i < 5; i++) {908saved_errno = errno;909errno = 0;910v = strtoul(ptr, &endptr, 16);911errno = saved_errno;912if (v > 0xff) {913warnx("Integer value %s not supported", str);914return (NULL);915}916if (*endptr != ':') {917warnx("Failed adding oid - %s",str);918return (NULL);919}920if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)921return (NULL);922ptr = endptr + 1;923}924925/* The last one - don't check the ending char here. */926saved_errno = errno;927errno = 0;928v = strtoul(ptr, &endptr, 16);929errno = saved_errno;930if (v > 0xff) {931warnx("Integer value %s not supported", str);932return (NULL);933}934if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)935return (NULL);936937return (endptr);938}939940static int32_t941parse_bridge_id(struct snmp_value *sv, char *string)942{943char *endptr;944int32_t i, saved_errno;945uint32_t v;946uint8_t bridge_id[SNMP_BRIDGEID_OCTETS];947948/* Read the priority. */949saved_errno = errno;950errno = 0;951v = strtoul(string, &endptr, 10);952953if (v > SNMP_MAX_BRIDGE_PRIORITY || errno != 0 || *endptr != '.') {954errno = saved_errno;955warnx("Bad bridge priority value %d", v);956return (-1);957}958959bridge_id[0] = (v & 0xff00);960bridge_id[1] = (v & 0xff);961962string = endptr + 1;963964for (i = 0; i < 5; i++) {965v = strtoul(string, &endptr, 16);966if (v > 0xff) {967warnx("Integer value %s not supported", string);968return (-1);969}970if(*endptr != ':') {971warnx("Failed reading octet - %s", string);972return (-1);973}974bridge_id[i + 2] = v;975string = endptr + 1;976}977978/* The last one - don't check the ending char here. */979v = strtoul(string, &endptr, 16);980if (v > 0xff) {981warnx("Integer value %s not supported", string);982return (-1);983}984bridge_id[7] = v;985986if ((sv->v.octetstring.octets = malloc(SNMP_BRIDGEID_OCTETS)) == NULL) {987syslog(LOG_ERR, "malloc failed: %s", strerror(errno));988return (-1);989}990991sv->v.octetstring.len = SNMP_BRIDGEID_OCTETS;992memcpy(sv->v.octetstring.octets, bridge_id, SNMP_BRIDGEID_OCTETS);993sv->syntax = SNMP_SYNTAX_OCTETSTRING;994return (1);995}996997/**************************************************************998* BridgePortId999**************************************************************1000* BEGEMOT-BRIDGE-MIB, LAST-UPDATED "200608100000Z"1001* BridgePortId ::= TEXTUAL-CONVENTION1002* DISPLAY-HINT "1x.1x"1003* STATUS current1004* DESCRIPTION1005* "A port identifier that contains a bridge port's STP priority1006* in the first octet and the port number in the second octet."1007* SYNTAX OCTET STRING (SIZE(2))1008*/1009static char *1010snmp_oct2bport_id(uint32_t len, char *octets, char *buf)1011{1012char *ptr;10131014if (len != SNMP_BPORT_OCTETS || octets == NULL || buf == NULL)1015return (NULL);10161017buf[0]= '\0';1018ptr = buf;10191020ptr += sprintf(ptr, "%d.", octets[0]);1021ptr += sprintf(ptr, "%d", octets[1]);10221023return (buf);1024}10251026static char *1027snmp_bport_id2oct(char *str, struct asn_oid *oid)1028{1029char *endptr, *ptr;1030uint32_t v;1031int saved_errno;10321033if (snmp_suboid_append(oid, (asn_subid_t) SNMP_BPORT_OCTETS) < 0)1034return (NULL);10351036ptr = str;1037/* Read the priority. */1038saved_errno = errno;1039errno = 0;1040v = strtoul(ptr, &endptr, 10);10411042if (v > SNMP_MAX_BPORT_PRIORITY || errno != 0 || *endptr != '.') {1043errno = saved_errno;1044warnx("Bad bridge port priority value %d", v);1045return (NULL);1046}10471048if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)1049return (NULL);10501051saved_errno = errno;1052errno = 0;1053v = strtoul(ptr, &endptr, 16);1054errno = saved_errno;10551056if (v > 0xff) {1057warnx("Bad port number - %d", v);1058return (NULL);1059}10601061if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)1062return (NULL);10631064return (endptr);1065}10661067static int32_t1068parse_bport_id(struct snmp_value *value, char *string)1069{1070char *endptr;1071int saved_errno;1072uint32_t v;1073uint8_t bport_id[SNMP_BPORT_OCTETS];10741075/* Read the priority. */1076saved_errno = errno;1077errno = 0;1078v = strtoul(string, &endptr, 10);10791080if (v > SNMP_MAX_BPORT_PRIORITY || errno != 0 || *endptr != '.') {1081errno = saved_errno;1082warnx("Bad bridge port priority value %d", v);1083return (-1);1084}10851086bport_id[0] = v;10871088string = endptr + 1;1089v = strtoul(string, &endptr, 16);1090if (v > 0xff) {1091warnx("Bad port number - %d", v);1092return (-1);1093}10941095bport_id[1] = v;10961097if ((value->v.octetstring.octets = malloc(SNMP_BPORT_OCTETS)) == NULL) {1098syslog(LOG_ERR, "malloc failed: %s", strerror(errno));1099return (-1);1100}11011102value->v.octetstring.len = SNMP_BPORT_OCTETS;1103memcpy(value->v.octetstring.octets, bport_id, SNMP_BPORT_OCTETS);1104value->syntax = SNMP_SYNTAX_OCTETSTRING;1105return (1);1106}1107/**************************************************************1108* InetAddress1109**************************************************************1110* INET-ADDRESS-MIB, REVISION "200502040000Z"1111* InetAddress ::= TEXTUAL-CONVENTION1112* STATUS current1113* DESCRIPTION1114* "Denotes a generic Internet address.1115*1116* An InetAddress value is always interpreted within the context1117* of an InetAddressType value. Every usage of the InetAddress1118* textual convention is required to specify the InetAddressType1119* object that provides the context. It is suggested that the1120* InetAddressType object be logically registered before the1121* object(s) that use the InetAddress textual convention, if1122* they appear in the same logical row.1123*1124* The value of an InetAddress object must always be1125* consistent with the value of the associated InetAddressType1126* object. Attempts to set an InetAddress object to a value1127* inconsistent with the associated InetAddressType1128* must fail with an inconsistentValue error.1129*1130* When this textual convention is used as the syntax of an1131* index object, there may be issues with the limit of 1281132* sub-identifiers specified in SMIv2, STD 58. In this case,1133* the object definition MUST include a 'SIZE' clause to1134* limit the number of potential instance sub-identifiers;1135* otherwise the applicable constraints MUST be stated in1136* the appropriate conceptual row DESCRIPTION clauses, or1137* in the surrounding documentation if there is no single1138* DESCRIPTION clause that is appropriate."1139* SYNTAX OCTET STRING (SIZE (0..255))1140**************************************************************1141* TODO: FIXME!!! syrinx: Since we do not support checking the1142* consistency of a varbinding based on the value of a previous1143* one, try to guess the type of address based on the1144* OctetString SIZE - 4 for IPv4, 16 for IPv6, others currently1145* not supported.1146*/1147static char *1148snmp_oct2inetaddr(uint32_t len, char *octets, char *buf)1149{1150int af;1151void *ip;1152struct in_addr ipv4;1153struct in6_addr ipv6;11541155if (len > MAX_OCTSTRING_LEN || octets == NULL || buf == NULL)1156return (NULL);11571158switch (len) {1159/* XXX: FIXME - IPv4*/1160case 4:1161memcpy(&ipv4.s_addr, octets, sizeof(ipv4.s_addr));1162af = AF_INET;1163ip = &ipv4;1164break;11651166/* XXX: FIXME - IPv4*/1167case 16:1168memcpy(ipv6.s6_addr, octets, sizeof(ipv6.s6_addr));1169af = AF_INET6;1170ip = &ipv6;1171break;11721173default:1174return (NULL);1175}11761177if (inet_ntop(af, ip, buf, SNMP_INADDRS_STRSZ) == NULL) {1178warn("inet_ntop failed");1179return (NULL);1180}11811182return (buf);1183}11841185static char *1186snmp_inetaddr2oct(char *str __unused, struct asn_oid *oid __unused)1187{1188return (NULL);1189}11901191static int32_t1192parse_inetaddr(struct snmp_value *value __unused, char *string __unused)1193{1194return (-1);1195}11961197/**************************************************************1198* SNMP BITS type - XXX: FIXME1199**************************************************************/1200static char *1201snmp_oct2bits(uint32_t len, char *octets, char *buf)1202{1203int i, bits;1204uint64_t value;12051206if (len > sizeof(value) || octets == NULL || buf == NULL)1207return (NULL);12081209for (i = len, value = 0, bits = 0; i > 0; i--, bits += 8)1210value += octets[i] << bits;12111212buf[0]= '\0';1213sprintf(buf, "0x%llx.",(long long unsigned) value);12141215return (buf);1216}12171218static char *1219snmp_bits2oct(char *str, struct asn_oid *oid)1220{1221char *endptr;1222int i, size, bits, saved_errno;1223uint64_t v, mask = 0xFF00000000000000;12241225saved_errno = errno;1226errno = 0;12271228v = strtoull(str, &endptr, 16);1229if (errno != 0) {1230warn("Bad BITS value %s", str);1231errno = saved_errno;1232return (NULL);1233}12341235bits = 8;1236/* Determine length - up to 8 octets supported so far. */1237for (size = sizeof(v); size > 0; size--) {1238if ((v & mask) != 0)1239break;1240mask = mask >> bits;1241}12421243if (size == 0)1244size = 1;12451246if (snmp_suboid_append(oid, (asn_subid_t) size) < 0)1247return (NULL);12481249for (i = 0, bits = 0; i < size; i++, bits += 8)1250if (snmp_suboid_append(oid,1251(asn_subid_t)((v & mask) >> bits)) < 0)1252return (NULL);12531254return (endptr);1255}12561257static int32_t1258parse_bits(struct snmp_value *value, char *string)1259{1260char *endptr;1261int i, size, bits, saved_errno;1262uint64_t v, mask = 0xFF00000000000000;12631264saved_errno = errno;1265errno = 0;12661267v = strtoull(string, &endptr, 16);12681269if (errno != 0) {1270warn("Bad BITS value %s", string);1271errno = saved_errno;1272return (-1);1273}12741275bits = 8;1276/* Determine length - up to 8 octets supported so far. */1277for (size = sizeof(v); size > 0; size--) {1278if ((v & mask) != 0)1279break;1280mask = mask >> bits;1281}12821283if (size == 0)1284size = 1;12851286if ((value->v.octetstring.octets = malloc(size)) == NULL) {1287syslog(LOG_ERR, "malloc failed: %s", strerror(errno));1288return (-1);1289}12901291value->v.octetstring.len = size;1292for (i = 0, bits = 0; i < size; i++, bits += 8)1293value->v.octetstring.octets[i] = (v & mask) >> bits;1294value->syntax = SNMP_SYNTAX_OCTETSTRING;1295return (1);1296}129712981299