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