bsnmptc.c revision 299016
1293745Sbrueffer/*-
2293745Sbrueffer * Copyright (c) 2006 The FreeBSD Project
3293745Sbrueffer * All rights reserved.
4293745Sbrueffer *
5293745Sbrueffer * Author: Shteryana Shopova <syrinx@FreeBSD.org>
6293745Sbrueffer *
7293745Sbrueffer * Redistribution of this software and documentation and use in source and
8293745Sbrueffer * binary forms, with or without modification, are permitted provided that
9293745Sbrueffer * the following conditions are met:
10293745Sbrueffer *
11293745Sbrueffer * 1. Redistributions of source code or documentation must retain the above
12293745Sbrueffer *    copyright notice, this list of conditions and the following disclaimer.
13293745Sbrueffer * 2. Redistributions in binary form must reproduce the above copyright
14293745Sbrueffer *    notice, this list of conditions and the following disclaimer in the
15293745Sbrueffer *    documentation and/or other materials provided with the distribution.
16293745Sbrueffer *
17293745Sbrueffer * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18293745Sbrueffer * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19293745Sbrueffer * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20293745Sbrueffer * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21293745Sbrueffer * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22293745Sbrueffer * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23293745Sbrueffer * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24293745Sbrueffer * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25293745Sbrueffer * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26293745Sbrueffer * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27293745Sbrueffer * SUCH DAMAGE.
28293745Sbrueffer *
29293745Sbrueffer * Textual conventions for OctetStrings
30293745Sbrueffer *
31293745Sbrueffer * $FreeBSD: stable/10/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptc.c 299016 2016-05-04 00:14:50Z ngie $
32293745Sbrueffer */
33293745Sbrueffer
34293745Sbrueffer#include <sys/param.h>
35293745Sbrueffer#include <sys/queue.h>
36293745Sbrueffer#include <sys/socket.h>
37293745Sbrueffer#include <sys/uio.h>
38293745Sbrueffer
39293745Sbrueffer#include <ctype.h>
40293745Sbrueffer#include <err.h>
41293745Sbrueffer#include <errno.h>
42293745Sbrueffer#include <fcntl.h>
43293745Sbrueffer#include <stdio.h>
44293745Sbrueffer#include <stdlib.h>
45293745Sbrueffer#include <string.h>
46293745Sbrueffer#include <syslog.h>
47293745Sbrueffer#include <unistd.h>
48293745Sbrueffer
49293745Sbrueffer#include <arpa/inet.h>
50293745Sbrueffer#include <netinet/in.h>
51293745Sbrueffer
52293745Sbrueffer#include <bsnmp/asn1.h>
53293745Sbrueffer#include <bsnmp/snmp.h>
54293745Sbrueffer#include "bsnmptc.h"
55293745Sbrueffer#include "bsnmptools.h"
56293745Sbrueffer
57293745Sbrueffer/* OctetString, DisplayString */
58293745Sbruefferstatic char *snmp_oct2str(uint32_t, char *, char *);
59293745Sbruefferstatic char *snmp_str2asn_oid(char *, struct asn_oid *);
60293745Sbruefferstatic int parse_octetstring(struct snmp_value *, char *);
61293745Sbrueffer
62293745Sbrueffer/* DateAndTime */
63293745Sbruefferstatic char *snmp_octstr2date(uint32_t, char *, char *);
64293745Sbruefferstatic char *snmp_date2asn_oid(char * , struct asn_oid *);
65293745Sbruefferstatic int parse_dateandtime(struct snmp_value *, char *);
66293745Sbrueffer
67293745Sbrueffer/* PhysAddress */
68293745Sbruefferstatic char *snmp_oct2physAddr(uint32_t, char *, char *);
69293745Sbruefferstatic char *snmp_addr2asn_oid(char *, struct asn_oid *);
70293745Sbruefferstatic int parse_physaddress(struct snmp_value *, char *);
71293745Sbrueffer
72293745Sbrueffer/* NTPTimeStamp */
73293745Sbruefferstatic char *snmp_oct2ntp_ts(uint32_t, char *, char *);
74293745Sbruefferstatic char *snmp_ntp_ts2asn_oid(char *, struct asn_oid *);
75293745Sbruefferstatic int parse_ntp_ts(struct snmp_value *, char *);
76293745Sbrueffer
77293745Sbrueffer/* BridgeId */
78293745Sbruefferstatic char *snmp_oct2bridgeid(uint32_t, char *, char *);
79293745Sbruefferstatic char *snmp_bridgeid2oct(char *, struct asn_oid *);
80293745Sbruefferstatic int parse_bridge_id(struct snmp_value *, char *);
81293745Sbrueffer
82293745Sbrueffer/* BridgePortId */
83293745Sbruefferstatic char *snmp_oct2bport_id(uint32_t, char *, char *);
84293745Sbruefferstatic char *snmp_bport_id2oct(char *, struct asn_oid *);
85293745Sbruefferstatic int parse_bport_id(struct snmp_value *, char *);
86293745Sbrueffer
87293745Sbrueffer/* InetAddress */
88293745Sbruefferstatic char *snmp_oct2inetaddr(uint32_t len, char *octets, char *buf);
89293745Sbruefferstatic char *snmp_inetaddr2oct(char *str, struct asn_oid *oid);
90293745Sbruefferstatic int32_t parse_inetaddr(struct snmp_value *value, char *string);
91293745Sbrueffer
92293745Sbruefferstatic char *snmp_oct2bits(uint32_t len, char *octets, char *buf);
93293745Sbruefferstatic char *snmp_bits2oct(char *str, struct asn_oid *oid);
94293745Sbruefferstatic int32_t parse_bits(struct snmp_value *value, char *string);
95293745Sbrueffer
96293745Sbruefferstruct snmp_text_conv {
97293745Sbrueffer	enum snmp_tc	tc;
98	const char	*tc_str;
99	int32_t		len;
100	snmp_oct2tc_f	oct2tc;
101	snmp_tc2oid_f	tc2oid;
102	snmp_tc2oct_f	tc2oct;
103} text_convs[] = {
104	{ SNMP_STRING, "OctetString", SNMP_VAR_STRSZ,
105	  snmp_oct2str, snmp_str2asn_oid, parse_octetstring },
106
107	{ SNMP_DISPLAYSTRING, "DisplayString" , SNMP_VAR_STRSZ,
108	  snmp_oct2str, snmp_str2asn_oid, parse_octetstring },
109
110	{ SNMP_DATEANDTIME, "DateAndTime", SNMP_DATETIME_STRSZ,
111	  snmp_octstr2date, snmp_date2asn_oid, parse_dateandtime },
112
113	{ SNMP_PHYSADDR, "PhysAddress", SNMP_PHYSADDR_STRSZ,
114	  snmp_oct2physAddr, snmp_addr2asn_oid, parse_physaddress },
115
116	{ SNMP_ATMESI, "AtmESI", SNMP_PHYSADDR_STRSZ,
117	  snmp_oct2physAddr, snmp_addr2asn_oid, parse_physaddress },
118
119	{ SNMP_NTP_TIMESTAMP, "NTPTimeStamp", SNMP_NTP_TS_STRSZ,
120	  snmp_oct2ntp_ts, snmp_ntp_ts2asn_oid, parse_ntp_ts },
121
122	{ SNMP_MACADDRESS, "MacAddress", SNMP_PHYSADDR_STRSZ,
123	  snmp_oct2physAddr, snmp_addr2asn_oid, parse_physaddress },
124
125	{ SNMP_BRIDGE_ID, "BridgeId", SNMP_BRIDGEID_STRSZ,
126	  snmp_oct2bridgeid, snmp_bridgeid2oct, parse_bridge_id },
127
128	{ SNMP_BPORT_ID, "BridgePortId", SNMP_BPORT_STRSZ,
129	  snmp_oct2bport_id, snmp_bport_id2oct, parse_bport_id },
130
131	{ SNMP_INETADDRESS, "InetAddress", SNMP_INADDRS_STRSZ,
132	  snmp_oct2inetaddr, snmp_inetaddr2oct, parse_inetaddr },
133
134	{ SNMP_TC_OWN, "BITS", SNMP_VAR_STRSZ,
135	  snmp_oct2bits, snmp_bits2oct, parse_bits },
136
137	{ SNMP_UNKNOWN, "Unknown", SNMP_VAR_STRSZ, snmp_oct2str,
138	  snmp_str2asn_oid, parse_octetstring }	/* keep last */
139};
140
141/* Common API */
142enum snmp_tc
143snmp_get_tc(char *str)
144{
145	int i;
146	for (i = 0; i < SNMP_UNKNOWN; i++) {
147		if (!strncmp(text_convs[i].tc_str, str,
148		    strlen(text_convs[i].tc_str)))
149			return (text_convs[i].tc);
150	}
151
152	return (SNMP_STRING);
153}
154
155char *
156snmp_oct2tc(enum snmp_tc tc, uint32_t len, char *octets)
157{
158	uint32_t tc_len;
159	char * buf;
160
161	if (tc < 0 || tc > SNMP_UNKNOWN)
162		tc = SNMP_UNKNOWN;
163
164	if (text_convs[tc].len > 0)
165		tc_len = text_convs[tc].len;
166	else
167		tc_len = 2 * len + 3;
168
169	if ((buf = malloc(tc_len)) == NULL ) {
170		syslog(LOG_ERR, "malloc failed - %s", strerror(errno));
171		return (NULL);
172	}
173
174	memset(buf, 0, tc_len);
175	if (text_convs[tc].oct2tc(len, octets, buf) == NULL) {
176		free(buf);
177		return (NULL);
178	}
179
180	return (buf);
181}
182
183char *
184snmp_tc2oid(enum snmp_tc tc, char *str, struct asn_oid *oid)
185{
186	if (tc < 0 || tc > SNMP_UNKNOWN)
187		tc = SNMP_UNKNOWN;
188
189	return (text_convs[tc].tc2oid(str, oid));
190}
191
192int32_t
193snmp_tc2oct(enum snmp_tc tc, struct snmp_value *value, char *string)
194{
195	if (tc < 0 || tc > SNMP_UNKNOWN)
196		tc = SNMP_UNKNOWN;
197
198	return (text_convs[tc].tc2oct(value, string));
199}
200
201/*****************************************************
202* Basic OctetString type.
203*/
204static char *
205snmp_oct2str(uint32_t len, char *octets, char *buf)
206{
207	uint8_t binary = 0;
208	uint32_t i;
209	char *ptr;
210
211	if (len > MAX_OCTSTRING_LEN || octets == NULL || buf == NULL)
212		return (NULL);
213
214	for (ptr = buf, i = 0; i < len; i++)
215		if (!isprint(octets[i])) {
216			binary = 1;
217			buf += sprintf(buf, "0x");
218			break;
219		}
220
221	for (ptr = buf, i = 0; i < len; i++)
222		if (!binary)
223			ptr += sprintf(ptr, "%c", octets[i]);
224		else
225			ptr += sprintf(ptr, "%2.2x", (u_char)octets[i]);
226
227	return (buf);
228}
229
230static char *
231snmp_str2asn_oid(char *str, struct asn_oid *oid)
232{
233	uint32_t i, len = 0;
234
235	/*
236	 * OctetStrings are allowed max length of ASN_MAXOCTETSTRING,
237	 * but trying to index an entry with such a long OctetString
238	 * will fail anyway.
239	 */
240	for (len = 0; len < ASN_MAXOIDLEN; len++) {
241		if (strchr(",]", *(str + len)) != NULL)
242			break;
243	}
244
245	if (len >= ASN_MAXOIDLEN)
246		return (NULL);
247
248	if (snmp_suboid_append(oid, (asn_subid_t) len) < 0)
249		return (NULL);
250
251	for (i = 0; i < len; i++)
252		if (snmp_suboid_append(oid, (asn_subid_t) *(str + i)) < 0)
253			return (NULL);
254
255	return (str + len);
256}
257
258static int32_t
259parse_octetstring(struct snmp_value *value, char *val)
260{
261	size_t len;
262
263	if ((len = strlen(val)) >= MAX_OCTSTRING_LEN) {
264		warnx("Octetstring too long - %d is max allowed",
265		    MAX_OCTSTRING_LEN - 1);
266		return (-1);
267	}
268
269	value->v.octetstring.len = len;
270
271	if((value->v.octetstring.octets = malloc(len)) == NULL) {
272		syslog(LOG_ERR,"malloc failed: %s", strerror(errno));
273		return (-1);
274	}
275
276	memcpy(value->v.octetstring.octets, val, len);
277	value->syntax = SNMP_SYNTAX_OCTETSTRING;
278
279	return (0);
280}
281
282/*************************************************************
283 * DateAndTime
284 *************************************************************
285 * rfc 2579 specification:
286 * DateAndTime ::= TEXTUAL-CONVENTION
287 *   DISPLAY-HINT "2d-1d-1d,1d:1d:1d.1d,1a1d:1d"
288 *   STATUS	  current
289 *   DESCRIPTION
290 *	"A date-time specification.
291 *
292 *	field	octets	contents		range
293 *	-----	------	--------		-----
294 *	1	1-2	year*			0..65536
295 *	2	3	month			1..12
296 *	3	4	day			1..31
297 *	4	5	hour			0..23
298 *	5	6	minutes			0..59
299 *	6	7	seconds			0..60
300 *			(use 60 for leap-second)
301 *	7	8	deci-seconds		0..9
302 *	8	9	direction from UTC	'+' / '-'
303 *	9	10	hours from UTC*		0..13
304 *	10	11	minutes from UTC	0..59
305 *
306 *	* Notes:
307 *	    - the value of year is in network-byte order
308 *	    - daylight saving time in New Zealand is +13
309 *
310 *	For example, Tuesday May 26, 1992 at 1:30:15 PM EDT would be
311 *	displayed as:
312 *
313 *		1992-5-26,13:30:15.0,-4:0
314 */
315static char *
316snmp_octstr2date(uint32_t len, char *octets, char *buf)
317{
318	int year;
319	char *ptr;
320
321	if (len != SNMP_DATETIME_OCTETS || octets == NULL || buf == NULL)
322		return (NULL);
323
324	buf[0]= '\0';
325	year = (octets[0] << 8);
326	year += (octets[1]);
327
328	ptr = buf;
329	ptr += sprintf(ptr, "%4.4d-%.2d-%.2d, ", year, octets[2],octets[3]);
330	ptr += sprintf(ptr, "%2.2d:%2.2d:%2.2d.%.2d, ", octets[4],octets[5],
331	    octets[6],octets[7]);
332	ptr += sprintf(ptr, "%c%.2d:%.2d", octets[8],octets[9],octets[10]);
333
334	return (buf);
335}
336
337static char *
338snmp_date2asn_oid(char *str, struct asn_oid *oid)
339{
340	char *endptr, *ptr;
341	static const char UTC[3] = "UTC";
342	int32_t saved_errno;
343	uint32_t v;
344
345	if (snmp_suboid_append(oid, (asn_subid_t) SNMP_DATETIME_OCTETS) < 0)
346		return (NULL);
347
348	/* Read 'YYYY-' and write it in two subs. */
349	ptr = str;
350	saved_errno = errno;
351	errno = 0;
352	v = strtoul(ptr, &endptr, 10);
353	if (v > 0xffff)
354		goto error;
355	else
356		errno = saved_errno;
357	if (*endptr != '-')
358		goto error1;
359	if (snmp_suboid_append(oid, (asn_subid_t) ((v & 0xff00) >> 8)) < 0)
360		return (NULL);
361	if (snmp_suboid_append(oid, (asn_subid_t) (v & 0xff)) < 0)
362		return (NULL);
363
364	/* 'MM-' */
365	ptr = endptr + 1;
366	saved_errno = errno;
367	v = strtoul(ptr, &endptr, 10);
368	if (errno != 0)
369		goto error;
370	else
371		errno = saved_errno;
372	if (*endptr != '-')
373		goto error1;
374	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
375		return (NULL);
376
377	/* 'DD,' */
378	ptr = endptr + 1;
379	saved_errno = errno;
380	v = strtoul(ptr, &endptr, 10);
381	if (errno != 0)
382		goto error;
383	else
384		errno = saved_errno;
385	if (*endptr != '-')
386		goto error1;
387	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
388		return (NULL);
389
390	/* 'HH:' */
391	ptr = endptr + 1;
392	saved_errno = errno;
393	v = strtoul(ptr, &endptr, 10);
394	if (errno != 0)
395		goto error;
396	else
397		errno = saved_errno;
398	if (*endptr != ':')
399		goto error1;
400	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
401		return (NULL);
402
403	/* 'MM:' */
404	ptr = endptr + 1;
405	saved_errno = errno;
406	v = strtoul(ptr, &endptr, 10);
407	if (errno != 0)
408		goto error;
409	else
410		errno = saved_errno;
411	if (*endptr != ':')
412		goto error1;
413	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
414		return (NULL);
415
416	/* 'SS.' */
417	ptr = endptr + 1;
418	saved_errno = errno;
419	v = strtoul(ptr, &endptr, 10);
420	if (errno != 0)
421		goto error;
422	else
423		errno = saved_errno;
424	if (*endptr != '.')
425		goto error1;
426	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
427		return (NULL);
428
429	/* 'M(mseconds),' */
430	ptr = endptr + 1;
431	saved_errno = errno;
432	v = strtoul(ptr, &endptr, 10);
433	if (errno != 0)
434		goto error;
435	else
436		errno = saved_errno;
437	if (*endptr != ',')
438		goto error1;
439	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
440		return (NULL);
441
442	/* 'UTC' - optional */
443	ptr = endptr + 1;
444	if (strncmp(ptr, UTC, sizeof(UTC)) == 0)
445		ptr += sizeof(UTC);
446
447	/* '+/-' */
448	if (*ptr == '-' || *ptr == '+') {
449		if (snmp_suboid_append(oid, (asn_subid_t) (*ptr)) < 0)
450			return (NULL);
451	} else
452		goto error1;
453
454	/* 'HH:' */
455	ptr = endptr + 1;
456	saved_errno = errno;
457	v = strtoul(ptr, &endptr, 10);
458	if (errno != 0)
459		goto error;
460	else
461		errno = saved_errno;
462	if (*endptr != ':')
463		goto error1;
464	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
465		return (NULL);
466
467	/* 'MM' - last one - ignore endptr here. */
468	ptr = endptr + 1;
469	saved_errno = errno;
470	v = strtoul(ptr, &endptr, 10);
471	if (errno != 0)
472		goto error;
473	else
474		errno = saved_errno;
475	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
476		return (NULL);
477
478	return (endptr);
479
480  error:
481	errno = saved_errno;
482  error1:
483	warnx("Date value %s not supported", str);
484	return (NULL);
485}
486
487/* Read a DateAndTime string eg. 1992-5-26,13:30:15.0,-4:0. */
488static int32_t
489parse_dateandtime(struct snmp_value *sv, char *val)
490{
491	char *endptr;
492	uint32_t v;
493	uint8_t	date[SNMP_DATETIME_OCTETS];
494
495	/* 'YYYY-' */
496	v = strtoul(val, &endptr, 10);
497	if (v > 0xffff || *endptr != '-')
498		goto error;
499	date[0] = ((v & 0xff00) >> 8);
500	date[1] = (v & 0xff);
501	val = endptr + 1;
502
503	/* 'MM-' */
504	v = strtoul(val, &endptr, 10);
505	if (v == 0 || v > 12 || *endptr != '-')
506		goto error;
507	date[2] = v;
508	val = endptr + 1;
509
510	/* 'DD,' */
511	v = strtoul(val, &endptr, 10);
512	if (v == 0 || v > 31 || *endptr != ',')
513		goto error;
514	date[3] = v;
515	val = endptr + 1;
516
517	/* 'HH:' */
518	v = strtoul(val, &endptr, 10);
519	if (v > 23 || *endptr != ':')
520		goto error;
521	date[4] = v;
522	val = endptr + 1;
523
524	/* 'MM:' */
525	v = strtoul(val, &endptr, 10);
526	if (v > 59 || *endptr != ':')
527		goto error;
528	date[5] = v;
529	val = endptr + 1;
530
531	/* 'SS.' */
532	v = strtoul(val, &endptr, 10);
533	if (v > 60 || *endptr != '.')
534		goto error;
535	date[6] = v;
536	val = endptr + 1;
537
538	/* '(deci-)s,' */
539	v = strtoul(val, &endptr, 10);
540	if (v > 9 || *endptr != ',')
541		goto error;
542	date[7] = v;
543	val = endptr + 1;
544
545	/* offset - '+/-' */
546	if (*val != '-' && *val != '+')
547		goto error;
548	date[8] = (uint8_t) *val;
549	val = endptr + 1;
550
551	/* 'HH:' - offset from UTC */
552	v = strtoul(val, &endptr, 10);
553	if (v > 13 || *endptr != ':')
554		goto error;
555	date[9] = v;
556	val = endptr + 1;
557
558	/* 'MM'\0''  offset from UTC */
559	v = strtoul(val, &endptr, 10);
560	if (v > 59 || *endptr != '\0')
561		goto error;
562	date[10] = v;
563
564	if ((sv->v.octetstring.octets = malloc(SNMP_DATETIME_OCTETS)) == NULL) {
565		warnx("malloc() failed - %s", strerror(errno));
566		return (-1);
567	}
568
569	sv->v.octetstring.len = SNMP_DATETIME_OCTETS;
570	memcpy(sv->v.octetstring.octets, date, SNMP_DATETIME_OCTETS);
571	sv->syntax = SNMP_SYNTAX_OCTETSTRING;
572	return (1);
573
574  error:
575	warnx("Date value %s not supported", val);
576	return (-1);
577}
578
579/**************************************************************
580 * PhysAddress
581 */
582static char *
583snmp_oct2physAddr(uint32_t len, char *octets, char *buf)
584{
585	char *ptr;
586	uint32_t i;
587
588	if (len != SNMP_PHYSADDR_OCTETS || octets == NULL || buf == NULL)
589		return (NULL);
590
591	buf[0]= '\0';
592
593	ptr = buf;
594	ptr += sprintf(ptr, "%2.2x", octets[0]);
595	for (i = 1; i < 6; i++)
596		ptr += sprintf(ptr, ":%2.2x", octets[i]);
597
598	return (buf);
599}
600
601static char *
602snmp_addr2asn_oid(char *str, struct asn_oid *oid)
603{
604	char *endptr, *ptr;
605	uint32_t v, i;
606	int saved_errno;
607
608	if (snmp_suboid_append(oid, (asn_subid_t) SNMP_PHYSADDR_OCTETS) < 0)
609		return (NULL);
610
611	ptr = str;
612	for (i = 0; i < 5; i++) {
613		saved_errno = errno;
614		v = strtoul(ptr, &endptr, 16);
615		errno = saved_errno;
616		if (v > 0xff) {
617			warnx("Integer value %s not supported", str);
618			return (NULL);
619		}
620		if (*endptr != ':') {
621			warnx("Failed adding oid - %s",str);
622			return (NULL);
623		}
624		if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
625			return (NULL);
626		ptr = endptr + 1;
627	}
628
629	/* The last one - don't check the ending char here. */
630	saved_errno = errno;
631	v = strtoul(ptr, &endptr, 16);
632	errno = saved_errno;
633	if (v > 0xff) {
634		warnx("Integer value %s not supported", str);
635		return (NULL);
636	}
637	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
638		return (NULL);
639
640	return (endptr);
641}
642
643static int32_t
644parse_physaddress(struct snmp_value *sv, char *val)
645{
646	char *endptr;
647	int32_t i;
648	uint32_t v;
649	uint8_t	phys_addr[SNMP_PHYSADDR_OCTETS];
650
651	for (i = 0; i < 5; i++) {
652		v = strtoul(val, &endptr, 16);
653		if (v > 0xff) {
654			warnx("Integer value %s not supported", val);
655			return (-1);
656		}
657		if(*endptr != ':') {
658			warnx("Failed reading octet - %s", val);
659			return (-1);
660		}
661		phys_addr[i] = v;
662		val = endptr + 1;
663	}
664
665	/* The last one - don't check the ending char here. */
666	v = strtoul(val, &endptr, 16);
667	if (v > 0xff) {
668		warnx("Integer value %s not supported", val);
669		return (-1);
670	}
671	phys_addr[5] = v;
672
673	if ((sv->v.octetstring.octets = malloc(SNMP_PHYSADDR_OCTETS)) == NULL) {
674		syslog(LOG_ERR,"malloc failed: %s", strerror(errno));
675		return (-1);
676	}
677
678	sv->v.octetstring.len = SNMP_PHYSADDR_OCTETS;
679	memcpy(sv->v.octetstring.octets, phys_addr, SNMP_PHYSADDR_OCTETS);
680	sv->syntax = SNMP_SYNTAX_OCTETSTRING;
681	return (1);
682}
683
684/**************************************************************
685 * NTPTimeStamp
686 **************************************************************
687 * NTP MIB, Revision 0.2, 7/25/97:
688 * NTPTimeStamp ::= TEXTUAL-CONVENTION
689 *    DISPLAY-HINT "4x.4x"
690 *    STATUS	current
691 *    DESCRIPTION
692 *	""
693 *    SYNTAX	OCTET STRING (SIZE(8))
694 */
695static char *
696snmp_oct2ntp_ts(uint32_t len, char *octets, char *buf)
697{
698	char *ptr;
699	uint32_t i;
700
701	if (len != SNMP_NTP_TS_OCTETS || octets == NULL || buf == NULL)
702		return (NULL);
703
704	buf[0]= '\0';
705
706	ptr = buf;
707	i = octets[0] * 1000 + octets[1] * 100 + octets[2] * 10 + octets[3];
708	ptr += sprintf(ptr, "%4.4d", i);
709	i = octets[4] * 1000 + octets[5] * 100 + octets[6] * 10 + octets[7];
710	ptr += sprintf(ptr, ".%4.4d", i);
711
712	return (buf);
713}
714
715static char *
716snmp_ntp_ts2asn_oid(char *str, struct asn_oid *oid)
717{
718	char *endptr, *ptr;
719	uint32_t v, i, d;
720	struct asn_oid suboid;
721	int saved_errno;
722
723	if (snmp_suboid_append(oid, (asn_subid_t) SNMP_NTP_TS_OCTETS) < 0)
724		return (NULL);
725
726	ptr = str;
727	saved_errno = errno;
728	v = strtoul(ptr, &endptr, 10);
729	if (errno != 0 || (v / 1000) > 9) {
730		warnx("Integer value %s not supported", str);
731		errno = saved_errno;
732		return (NULL);
733	} else
734		errno = saved_errno;
735
736	if (*endptr != '.') {
737		warnx("Failed adding oid - %s",str);
738		return (NULL);
739	}
740
741	memset(&suboid, 0, sizeof(struct asn_oid));
742	suboid.len = SNMP_NTP_TS_OCTETS;
743
744	for (i = 0, d = 1000; i < 4; i++) {
745		suboid.subs[i] = v / d;
746		v = v % d;
747		d = d / 10;
748	}
749
750	ptr = endptr + 1;
751	saved_errno = errno;
752	v = strtoul(ptr, &endptr, 10);
753	if (errno != 0 || (v / 1000) > 9) {
754		warnx("Integer value %s not supported", str);
755		errno = saved_errno;
756		return (NULL);
757	} else
758		errno = saved_errno;
759
760	for (i = 0, d = 1000; i < 4; i++) {
761		suboid.subs[i + 4] = v / d;
762		v = v % d;
763		d = d / 10;
764	}
765
766	asn_append_oid(oid, &suboid);
767	return (endptr);
768}
769
770static int32_t
771parse_ntp_ts(struct snmp_value *sv, char *val)
772{
773	char *endptr;
774	int32_t i, d, saved_errno;
775	uint32_t v;
776	uint8_t	ntp_ts[SNMP_NTP_TS_OCTETS];
777
778	saved_errno = errno;
779	v = strtoul(val, &endptr, 10);
780	if (errno != 0 || (v / 1000) > 9) {
781		saved_errno = errno;
782		warnx("Integer value %s not supported", val);
783		return (-1);
784	} else
785		saved_errno = errno;
786
787	if (*endptr != '.') {
788		warnx("Failed reading octet - %s", val);
789		return (-1);
790	}
791
792	for (i = 0, d = 1000; i < 4; i++) {
793		ntp_ts[i] = v / d;
794		v = v % d;
795		d = d / 10;
796	}
797	val = endptr + 1;
798
799	saved_errno = errno;
800	v = strtoul(val, &endptr, 10);
801	if (errno != 0 || (v / 1000) > 9) {
802		saved_errno = errno;
803		warnx("Integer value %s not supported", val);
804		return (-1);
805	} else
806		saved_errno = errno;
807
808	for (i = 0, d = 1000; i < 4; i++) {
809		ntp_ts[i + 4] = v / d;
810		v = v % d;
811		d = d / 10;
812	}
813
814	if ((sv->v.octetstring.octets = malloc(SNMP_NTP_TS_OCTETS)) == NULL) {
815		syslog(LOG_ERR,"malloc failed: %s", strerror(errno));
816		return (-1);
817	}
818
819	sv->v.octetstring.len = SNMP_NTP_TS_OCTETS;
820	memcpy(sv->v.octetstring.octets, ntp_ts, SNMP_NTP_TS_OCTETS);
821	sv->syntax = SNMP_SYNTAX_OCTETSTRING;
822	return (1);
823}
824
825/**************************************************************
826 * BridgeId
827 **************************************************************
828 * BRIDGE-MIB, REVISION		"200509190000Z"
829 * BridgeId ::= TEXTUAL-CONVENTION
830 *    STATUS	current
831 *    DESCRIPTION
832 *	"The Bridge-Identifier, as used in the Spanning Tree
833 *	Protocol, to uniquely identify a bridge.  Its first two
834 *	octets (in network byte order) contain a priority value,
835 *	and its last 6 octets contain the MAC address used to
836 *	refer to a bridge in a unique fashion (typically, the
837 *	numerically smallest MAC address of all ports on the
838 *	bridge)."
839 *    SYNTAX	OCTET STRING (SIZE (8))
840 */
841static char *
842snmp_oct2bridgeid(uint32_t len, char *octets, char *buf)
843{
844	char *ptr;
845	uint32_t i, priority;
846
847	if (len != SNMP_BRIDGEID_OCTETS || octets == NULL || buf == NULL)
848		return (NULL);
849
850	buf[0]= '\0';
851	ptr = buf;
852
853	priority = octets[0] << 8;
854	priority += octets[1];
855	if (priority > SNMP_MAX_BRIDGE_PRIORITY) {
856		warnx("Invalid bridge priority %d", priority);
857		return (NULL);
858	} else
859		ptr += sprintf(ptr, "%d.", octets[0]);
860
861	ptr += sprintf(ptr, "%2.2x", octets[2]);
862
863	for (i = 1; i < 6; i++)
864		ptr += sprintf(ptr, ":%2.2x", octets[i + 2]);
865
866	return (buf);
867}
868
869static char *
870snmp_bridgeid2oct(char *str, struct asn_oid *oid)
871{
872	char *endptr, *ptr;
873	uint32_t v, i;
874	int32_t saved_errno;
875
876	if (snmp_suboid_append(oid, (asn_subid_t) SNMP_BRIDGEID_OCTETS) < 0)
877		return (NULL);
878
879	ptr = str;
880	/* Read the priority. */
881	saved_errno = errno;
882	v = strtoul(ptr, &endptr, 10);
883	errno = 0;
884
885	if (v > SNMP_MAX_BRIDGE_PRIORITY || errno != 0 || *endptr != '.') {
886		errno = saved_errno;
887		warnx("Bad bridge priority value %d", v);
888		return (NULL);
889	}
890
891	if (snmp_suboid_append(oid, (asn_subid_t) (v & 0xff00)) < 0)
892		return (NULL);
893
894	if (snmp_suboid_append(oid, (asn_subid_t) (v & 0xff)) < 0)
895		return (NULL);
896
897	ptr = endptr + 1;
898	for (i = 0; i < 5; i++) {
899		saved_errno = errno;
900		v = strtoul(ptr, &endptr, 16);
901		errno = saved_errno;
902		if (v > 0xff) {
903			warnx("Integer value %s not supported", str);
904			return (NULL);
905		}
906		if (*endptr != ':') {
907			warnx("Failed adding oid - %s",str);
908			return (NULL);
909		}
910		if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
911			return (NULL);
912		ptr = endptr + 1;
913	}
914
915	/* The last one - don't check the ending char here. */
916	saved_errno = errno;
917	v = strtoul(ptr, &endptr, 16);
918	errno = saved_errno;
919	if (v > 0xff) {
920		warnx("Integer value %s not supported", str);
921		return (NULL);
922	}
923	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
924		return (NULL);
925
926	return (endptr);
927}
928
929static int32_t
930parse_bridge_id(struct snmp_value *sv, char *string)
931{
932	char *ptr, *endptr;
933	int32_t i, saved_errno;
934	uint32_t v;
935	uint8_t	bridge_id[SNMP_BRIDGEID_OCTETS];
936
937	ptr = string;
938	/* Read the priority. */
939	saved_errno = errno;
940	errno = 0;
941	v = strtoul(string, &endptr, 10);
942	errno = saved_errno;
943
944	if (v > SNMP_MAX_BRIDGE_PRIORITY || errno != 0 || *endptr != '.') {
945		errno = saved_errno;
946		warnx("Bad bridge priority value %d", v);
947		return (-1);
948	}
949
950	bridge_id[0] = (v & 0xff00);
951	bridge_id[1] = (v & 0xff);
952
953	string = endptr + 1;
954
955	for (i = 0; i < 5; i++) {
956		v = strtoul(string, &endptr, 16);
957		if (v > 0xff) {
958			warnx("Integer value %s not supported", string);
959			return (-1);
960		}
961		if(*endptr != ':') {
962			warnx("Failed reading octet - %s", string);
963			return (-1);
964		}
965		bridge_id[i + 2] = v;
966		string = endptr + 1;
967	}
968
969	/* The last one - don't check the ending char here. */
970	v = strtoul(string, &endptr, 16);
971	if (v > 0xff) {
972		warnx("Integer value %s not supported", string);
973		return (-1);
974	}
975	bridge_id[7] = v;
976
977	if ((sv->v.octetstring.octets = malloc(SNMP_BRIDGEID_OCTETS)) == NULL) {
978		syslog(LOG_ERR,"malloc failed: %s", strerror(errno));
979		return (-1);
980	}
981
982	sv->v.octetstring.len = SNMP_BRIDGEID_OCTETS;
983	memcpy(sv->v.octetstring.octets, bridge_id, SNMP_BRIDGEID_OCTETS);
984	sv->syntax = SNMP_SYNTAX_OCTETSTRING;
985	return (1);
986}
987
988/**************************************************************
989 * BridgePortId
990 **************************************************************
991 * BEGEMOT-BRIDGE-MIB, LAST-UPDATED "200608100000Z"
992 * BridgePortId ::= TEXTUAL-CONVENTION
993 *    DISPLAY-HINT "1x.1x"
994 *    STATUS	current
995 *    DESCRIPTION
996 *	"A port identifier that contains a bridge port's STP priority
997 *	in the first octet and the port number in the second octet."
998 *    SYNTAX	OCTET STRING (SIZE(2))
999 */
1000static char *
1001snmp_oct2bport_id(uint32_t len, char *octets, char *buf)
1002{
1003	char *ptr;
1004
1005	if (len != SNMP_BPORT_OCTETS || octets == NULL || buf == NULL)
1006		return (NULL);
1007
1008	buf[0]= '\0';
1009	ptr = buf;
1010
1011	ptr += sprintf(ptr, "%d.", octets[0]);
1012	ptr += sprintf(ptr, "%d", octets[1]);
1013
1014	return (buf);
1015}
1016
1017static char *
1018snmp_bport_id2oct(char *str, struct asn_oid *oid)
1019{
1020	char *endptr, *ptr;
1021	uint32_t v;
1022	int saved_errno;
1023
1024	if (snmp_suboid_append(oid, (asn_subid_t) SNMP_BPORT_OCTETS) < 0)
1025		return (NULL);
1026
1027	ptr = str;
1028	/* Read the priority. */
1029	saved_errno = errno;
1030	v = strtoul(ptr, &endptr, 10);
1031	errno = 0;
1032
1033	if (v > SNMP_MAX_BPORT_PRIORITY || errno != 0 || *endptr != '.') {
1034		errno = saved_errno;
1035		warnx("Bad bridge port priority value %d", v);
1036		return (NULL);
1037	}
1038
1039	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
1040		return (NULL);
1041
1042	saved_errno = errno;
1043	v = strtoul(ptr, &endptr, 16);
1044	errno = saved_errno;
1045
1046	if (v > 0xff) {
1047		warnx("Bad port number - %d", v);
1048		return (NULL);
1049	}
1050
1051	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
1052		return (NULL);
1053
1054	return (endptr);
1055}
1056
1057static int32_t
1058parse_bport_id(struct snmp_value *value, char *string)
1059{
1060	char *ptr, *endptr;
1061	int saved_errno;
1062	uint32_t v;
1063	uint8_t	bport_id[SNMP_BPORT_OCTETS];
1064
1065	ptr = string;
1066	/* Read the priority. */
1067	saved_errno = errno;
1068	errno = 0;
1069	v = strtoul(string, &endptr, 10);
1070	errno = saved_errno;
1071
1072	if (v > SNMP_MAX_BPORT_PRIORITY || errno != 0 || *endptr != '.') {
1073		errno = saved_errno;
1074		warnx("Bad bridge port priority value %d", v);
1075		return (-1);
1076	}
1077
1078	bport_id[0] = v;
1079
1080	string = endptr + 1;
1081	v = strtoul(string, &endptr, 16);
1082	if (v > 0xff) {
1083		warnx("Bad port number - %d", v);
1084		return (-1);
1085	}
1086
1087	bport_id[1] = v;
1088
1089	if ((value->v.octetstring.octets = malloc(SNMP_BPORT_OCTETS)) == NULL) {
1090		syslog(LOG_ERR,"malloc failed: %s", strerror(errno));
1091		return (-1);
1092	}
1093
1094	value->v.octetstring.len = SNMP_BPORT_OCTETS;
1095	memcpy(value->v.octetstring.octets, bport_id, SNMP_BPORT_OCTETS);
1096	value->syntax = SNMP_SYNTAX_OCTETSTRING;
1097	return (1);
1098}
1099/**************************************************************
1100 * InetAddress
1101 **************************************************************
1102 * INET-ADDRESS-MIB, REVISION     "200502040000Z"
1103 * InetAddress ::= TEXTUAL-CONVENTION
1104 *   STATUS      current
1105 *   DESCRIPTION
1106 *       "Denotes a generic Internet address.
1107 *
1108 *        An InetAddress value is always interpreted within the context
1109 *        of an InetAddressType value.  Every usage of the InetAddress
1110 *        textual convention is required to specify the InetAddressType
1111 *        object that provides the context.  It is suggested that the
1112 *        InetAddressType object be logically registered before the
1113 *        object(s) that use the InetAddress textual convention, if
1114 *        they appear in the same logical row.
1115 *
1116 *        The value of an InetAddress object must always be
1117 *        consistent with the value of the associated InetAddressType
1118 *        object.  Attempts to set an InetAddress object to a value
1119 *        inconsistent with the associated InetAddressType
1120 *        must fail with an inconsistentValue error.
1121 *
1122 *        When this textual convention is used as the syntax of an
1123 *        index object, there may be issues with the limit of 128
1124 *        sub-identifiers specified in SMIv2, STD 58.  In this case,
1125 *        the object definition MUST include a 'SIZE' clause to
1126 *        limit the number of potential instance sub-identifiers;
1127 *        otherwise the applicable constraints MUST be stated in
1128 *        the appropriate conceptual row DESCRIPTION clauses, or
1129 *        in the surrounding documentation if there is no single
1130 *        DESCRIPTION clause that is appropriate."
1131 *   SYNTAX       OCTET STRING (SIZE (0..255))
1132 **************************************************************
1133 * TODO: FIXME!!! syrinx: Since we do not support checking the
1134 * consistency of a varbinding based on the value of a previous
1135 * one, try to guess the type of address based on the
1136 * OctetString SIZE - 4 for IPv4, 16 for IPv6, others currently
1137 * not supported.
1138 */
1139static char *
1140snmp_oct2inetaddr(uint32_t len, char *octets, char *buf)
1141{
1142	int af;
1143	void *ip;
1144	struct in_addr	ipv4;
1145	struct in6_addr	ipv6;
1146
1147	if (len > MAX_OCTSTRING_LEN || octets == NULL || buf == NULL)
1148		return (NULL);
1149
1150	switch (len) {
1151		/* XXX: FIXME - IPv4*/
1152		case 4:
1153			memcpy(&ipv4.s_addr, octets, sizeof(ipv4.s_addr));
1154			af = AF_INET;
1155			ip = &ipv4;
1156			break;
1157
1158		/* XXX: FIXME - IPv4*/
1159		case 16:
1160			memcpy(ipv6.s6_addr, octets, sizeof(ipv6.s6_addr));
1161			af = AF_INET6;
1162			ip = &ipv6;
1163			break;
1164
1165		default:
1166			return (NULL);
1167	}
1168
1169	if (inet_ntop(af, ip, buf, SNMP_INADDRS_STRSZ) == NULL) {
1170		warnx("inet_ntop failed - %s", strerror(errno));
1171		return (NULL);
1172	}
1173
1174	return (buf);
1175}
1176
1177static char *
1178snmp_inetaddr2oct(char *str, struct asn_oid *oid)
1179{
1180	return (NULL);
1181}
1182
1183static int32_t
1184parse_inetaddr(struct snmp_value *value, char *string)
1185{
1186	return (-1);
1187}
1188
1189/**************************************************************
1190 * SNMP BITS type - XXX: FIXME
1191 **************************************************************/
1192static char *
1193snmp_oct2bits(uint32_t len, char *octets, char *buf)
1194{
1195	int i, bits;
1196	uint64_t value;
1197
1198	if (len > sizeof(value) || octets == NULL || buf == NULL)
1199		return (NULL);
1200
1201	for (i = len, value = 0, bits = 0; i > 0; i--, bits += 8)
1202		value += octets[i] << bits;
1203
1204	buf[0]= '\0';
1205	sprintf(buf, "0x%llx.",(long long unsigned) value);
1206
1207	return (buf);
1208}
1209
1210static char *
1211snmp_bits2oct(char *str, struct asn_oid *oid)
1212{
1213	char *endptr;
1214	int i, size, bits, saved_errno;
1215	uint64_t v, mask = 0xFF00000000000000;
1216
1217	saved_errno = errno;
1218	errno = 0;
1219
1220	v = strtoull(str, &endptr, 16);
1221	if (errno != 0) {
1222		warnx("Bad BITS value %s - %s", str, strerror(errno));
1223		errno = saved_errno;
1224		return (NULL);
1225	}
1226
1227	bits = 8;
1228	/* Determine length - up to 8 octets supported so far. */
1229	for (size = sizeof(v); size > 0; size--) {
1230		if ((v & mask) != 0)
1231			break;
1232		mask = mask >> bits;
1233	}
1234
1235	if (size == 0)
1236		size = 1;
1237
1238	if (snmp_suboid_append(oid, (asn_subid_t) size) < 0)
1239		return (NULL);
1240
1241	for (i = 0, bits = 0; i < size; i++, bits += 8)
1242		if (snmp_suboid_append(oid,
1243		    (asn_subid_t)((v & mask) >> bits)) < 0)
1244			return (NULL);
1245
1246	return (endptr);
1247}
1248
1249static int32_t
1250parse_bits(struct snmp_value *value, char *string)
1251{
1252	char *endptr;
1253	int i, size, bits, saved_errno;
1254	uint64_t v, mask = 0xFF00000000000000;
1255
1256	saved_errno = errno;
1257	errno = 0;
1258
1259	v = strtoull(string, &endptr, 16);
1260
1261	if (errno != 0) {
1262		warnx("Bad BITS value %s - %s", string, strerror(errno));
1263		errno = saved_errno;
1264		return (-1);
1265	}
1266
1267	bits = 8;
1268	/* Determine length - up to 8 octets supported so far. */
1269	for (size = sizeof(v); size > 0; size--) {
1270		if ((v & mask) != 0)
1271			break;
1272		mask = mask >> bits;
1273	}
1274
1275	if (size == 0)
1276		size = 1;
1277
1278	if ((value->v.octetstring.octets = malloc(size)) == NULL) {
1279		syslog(LOG_ERR, "malloc failed: %s", strerror(errno));
1280		return (-1);
1281	}
1282
1283	value->v.octetstring.len = size;
1284	for (i = 0, bits = 0; i < size; i++, bits += 8)
1285		value->v.octetstring.octets[i] = (v & mask) >> bits;
1286	value->syntax = SNMP_SYNTAX_OCTETSTRING;
1287	return (1);
1288}
1289