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  * $FreeBSD$
32  */
33 
34 #include <sys/param.h>
35 #include <sys/queue.h>
36 #include <sys/socket.h>
37 #include <sys/uio.h>
38 
39 #include <ctype.h>
40 #include <err.h>
41 #include <errno.h>
42 #include <fcntl.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <syslog.h>
47 #include <unistd.h>
48 
49 #include <arpa/inet.h>
50 #include <netinet/in.h>
51 
52 #include <bsnmp/asn1.h>
53 #include <bsnmp/snmp.h>
54 #include "bsnmptc.h"
55 #include "bsnmptools.h"
56 
57 /* OctetString, DisplayString */
58 static char *snmp_oct2str(uint32_t, char *, char *);
59 static char *snmp_str2asn_oid(char *, struct asn_oid *);
60 static int parse_octetstring(struct snmp_value *, char *);
61 
62 /* DateAndTime */
63 static char *snmp_octstr2date(uint32_t, char *, char *);
64 static char *snmp_date2asn_oid(char * , struct asn_oid *);
65 static int parse_dateandtime(struct snmp_value *, char *);
66 
67 /* PhysAddress */
68 static char *snmp_oct2physAddr(uint32_t, char *, char *);
69 static char *snmp_addr2asn_oid(char *, struct asn_oid *);
70 static int parse_physaddress(struct snmp_value *, char *);
71 
72 /* NTPTimeStamp */
73 static char *snmp_oct2ntp_ts(uint32_t, char *, char *);
74 static char *snmp_ntp_ts2asn_oid(char *, struct asn_oid *);
75 static int parse_ntp_ts(struct snmp_value *, char *);
76 
77 /* BridgeId */
78 static char *snmp_oct2bridgeid(uint32_t, char *, char *);
79 static char *snmp_bridgeid2oct(char *, struct asn_oid *);
80 static int parse_bridge_id(struct snmp_value *, char *);
81 
82 /* BridgePortId */
83 static char *snmp_oct2bport_id(uint32_t, char *, char *);
84 static char *snmp_bport_id2oct(char *, struct asn_oid *);
85 static int parse_bport_id(struct snmp_value *, char *);
86 
87 /* InetAddress */
88 static char *snmp_oct2inetaddr(uint32_t len, char *octets, char *buf);
89 static char *snmp_inetaddr2oct(char *str, struct asn_oid *oid);
90 static int32_t parse_inetaddr(struct snmp_value *value, char *string);
91 
92 static char *snmp_oct2bits(uint32_t len, char *octets, char *buf);
93 static char *snmp_bits2oct(char *str, struct asn_oid *oid);
94 static int32_t parse_bits(struct snmp_value *value, char *string);
95 
96 struct snmp_text_conv {
97 	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 */
142 enum snmp_tc
143 snmp_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 
155 char *
156 snmp_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 
183 char *
184 snmp_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 
192 int32_t
193 snmp_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 */
204 static char *
205 snmp_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 
230 static char *
231 snmp_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 
258 static int32_t
259 parse_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  */
315 static char *
316 snmp_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 
337 static char *
338 snmp_date2asn_oid(char *str, struct asn_oid *oid)
339 {
340 	char *endptr, *ptr;
341 	uint32_t v;
342 	int32_t saved_errno;
343 
344 	if (snmp_suboid_append(oid, (asn_subid_t) SNMP_DATETIME_OCTETS) < 0)
345 		return (NULL);
346 
347 	/* Read 'YYYY-' and write it in two subs. */
348 	ptr = str;
349 	saved_errno = errno;
350 	errno = 0;
351 	v = strtoul(ptr, &endptr, 10);
352 	if (v > 0xffff)
353 		goto error;
354 	else
355 		errno = saved_errno;
356 	if (*endptr != '-')
357 		goto error1;
358 	if (snmp_suboid_append(oid, (asn_subid_t) ((v & 0xff00) >> 8)) < 0)
359 		return (NULL);
360 	if (snmp_suboid_append(oid, (asn_subid_t) (v & 0xff)) < 0)
361 		return (NULL);
362 
363 	/* 'MM-' */
364 	ptr = endptr + 1;
365 	saved_errno = errno;
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 	v = strtoul(ptr, &endptr, 10);
380 	if (errno != 0)
381 		goto error;
382 	else
383 		errno = saved_errno;
384 	if (*endptr != '-')
385 		goto error1;
386 	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
387 		return (NULL);
388 
389 	/* 'HH:' */
390 	ptr = endptr + 1;
391 	saved_errno = errno;
392 	v = strtoul(ptr, &endptr, 10);
393 	if (errno != 0)
394 		goto error;
395 	else
396 		errno = saved_errno;
397 	if (*endptr != ':')
398 		goto error1;
399 	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
400 		return (NULL);
401 
402 	/* 'MM:' */
403 	ptr = endptr + 1;
404 	saved_errno = errno;
405 	v = strtoul(ptr, &endptr, 10);
406 	if (errno != 0)
407 		goto error;
408 	else
409 		errno = saved_errno;
410 	if (*endptr != ':')
411 		goto error1;
412 	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
413 		return (NULL);
414 
415 	/* 'SS.' */
416 	ptr = endptr + 1;
417 	saved_errno = errno;
418 	v = strtoul(ptr, &endptr, 10);
419 	if (errno != 0)
420 		goto error;
421 	else
422 		errno = saved_errno;
423 	if (*endptr != '.')
424 		goto error1;
425 	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
426 		return (NULL);
427 
428 	/* 'M(mseconds),' */
429 	ptr = endptr + 1;
430 	saved_errno = errno;
431 	v = strtoul(ptr, &endptr, 10);
432 	if (errno != 0)
433 		goto error;
434 	else
435 		errno = saved_errno;
436 	if (*endptr != ',')
437 		goto error1;
438 	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
439 		return (NULL);
440 
441 	/* 'UTC' - optional */
442 	ptr = endptr + 1;
443 	if (*ptr == 'U' && *(ptr + 1) == 'T' && *(ptr + 1) == 'C')
444 		ptr += 3;
445 
446 	/* '+/-' */
447 	if (*ptr == '-' || *ptr == '+') {
448 		if (snmp_suboid_append(oid, (asn_subid_t) (*ptr)) < 0)
449 			return (NULL);
450 	} else
451 		goto error1;
452 
453 	/* 'HH:' */
454 	ptr = endptr + 1;
455 	saved_errno = errno;
456 	v = strtoul(ptr, &endptr, 10);
457 	if (errno != 0)
458 		goto error;
459 	else
460 		errno = saved_errno;
461 	if (*endptr != ':')
462 		goto error1;
463 	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
464 		return (NULL);
465 
466 	/* 'MM' - last one - ignore endptr here. */
467 	ptr = endptr + 1;
468 	saved_errno = errno;
469 	v = strtoul(ptr, &endptr, 10);
470 	if (errno != 0)
471 		goto error;
472 	else
473 		errno = saved_errno;
474 	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
475 		return (NULL);
476 
477 	return (endptr);
478 
479   error:
480 	errno = saved_errno;
481   error1:
482 	warnx("Date value %s not supported", str);
483 	return (NULL);
484 }
485 
486 /* Read a DateAndTime string eg. 1992-5-26,13:30:15.0,-4:0. */
487 static int32_t
488 parse_dateandtime(struct snmp_value *sv, char *val)
489 {
490 	char *endptr;
491 	uint32_t v;
492 	uint8_t	date[SNMP_DATETIME_OCTETS];
493 
494 	/* 'YYYY-' */
495 	v = strtoul(val, &endptr, 10);
496 	if (v > 0xffff || *endptr != '-')
497 		goto error;
498 	date[0] = ((v & 0xff00) >> 8);
499 	date[1] = (v & 0xff);
500 	val = endptr + 1;
501 
502 	/* 'MM-' */
503 	v = strtoul(val, &endptr, 10);
504 	if (v == 0 || v > 12 || *endptr != '-')
505 		goto error;
506 	date[2] = v;
507 	val = endptr + 1;
508 
509 	/* 'DD,' */
510 	v = strtoul(val, &endptr, 10);
511 	if (v == 0 || v > 31 || *endptr != ',')
512 		goto error;
513 	date[3] = v;
514 	val = endptr + 1;
515 
516 	/* 'HH:' */
517 	v = strtoul(val, &endptr, 10);
518 	if (v > 23 || *endptr != ':')
519 		goto error;
520 	date[4] = v;
521 	val = endptr + 1;
522 
523 	/* 'MM:' */
524 	v = strtoul(val, &endptr, 10);
525 	if (v > 59 || *endptr != ':')
526 		goto error;
527 	date[5] = v;
528 	val = endptr + 1;
529 
530 	/* 'SS.' */
531 	v = strtoul(val, &endptr, 10);
532 	if (v > 60 || *endptr != '.')
533 		goto error;
534 	date[6] = v;
535 	val = endptr + 1;
536 
537 	/* '(deci-)s,' */
538 	v = strtoul(val, &endptr, 10);
539 	if (v > 9 || *endptr != ',')
540 		goto error;
541 	date[7] = v;
542 	val = endptr + 1;
543 
544 	/* offset - '+/-' */
545 	if (*val != '-' && *val != '+')
546 		goto error;
547 	date[8] = (uint8_t) *val;
548 	val = endptr + 1;
549 
550 	/* 'HH:' - offset from UTC */
551 	v = strtoul(val, &endptr, 10);
552 	if (v > 13 || *endptr != ':')
553 		goto error;
554 	date[9] = v;
555 	val = endptr + 1;
556 
557 	/* 'MM'\0''  offset from UTC */
558 	v = strtoul(val, &endptr, 10);
559 	if (v > 59 || *endptr != '\0')
560 		goto error;
561 	date[10] = v;
562 
563 	if ((sv->v.octetstring.octets = malloc(SNMP_DATETIME_OCTETS)) == NULL) {
564 		warnx("malloc() failed - %s", strerror(errno));
565 		return (-1);
566 	}
567 
568 	sv->v.octetstring.len = SNMP_DATETIME_OCTETS;
569 	memcpy(sv->v.octetstring.octets, date, SNMP_DATETIME_OCTETS);
570 	sv->syntax = SNMP_SYNTAX_OCTETSTRING;
571 	return (1);
572 
573   error:
574 	warnx("Date value %s not supported", val);
575 	return (-1);
576 }
577 
578 /**************************************************************
579  * PhysAddress
580  */
581 static char *
582 snmp_oct2physAddr(uint32_t len, char *octets, char *buf)
583 {
584 	char *ptr;
585 	uint32_t i;
586 
587 	if (len != SNMP_PHYSADDR_OCTETS || octets == NULL || buf == NULL)
588 		return (NULL);
589 
590 	buf[0]= '\0';
591 
592 	ptr = buf;
593 	ptr += sprintf(ptr, "%2.2x", octets[0]);
594 	for (i = 1; i < 6; i++)
595 		ptr += sprintf(ptr, ":%2.2x", octets[i]);
596 
597 	return (buf);
598 }
599 
600 static char *
601 snmp_addr2asn_oid(char *str, struct asn_oid *oid)
602 {
603 	char *endptr, *ptr;
604 	uint32_t v, i;
605 	int saved_errno;
606 
607 	if (snmp_suboid_append(oid, (asn_subid_t) SNMP_PHYSADDR_OCTETS) < 0)
608 		return (NULL);
609 
610 	ptr = str;
611 	for (i = 0; i < 5; i++) {
612 		saved_errno = errno;
613 		v = strtoul(ptr, &endptr, 16);
614 		errno = saved_errno;
615 		if (v > 0xff) {
616 			warnx("Integer value %s not supported", str);
617 			return (NULL);
618 		}
619 		if (*endptr != ':') {
620 			warnx("Failed adding oid - %s",str);
621 			return (NULL);
622 		}
623 		if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
624 			return (NULL);
625 		ptr = endptr + 1;
626 	}
627 
628 	/* The last one - don't check the ending char here. */
629 	saved_errno = errno;
630 	v = strtoul(ptr, &endptr, 16);
631 	errno = saved_errno;
632 	if (v > 0xff) {
633 		warnx("Integer value %s not supported", str);
634 		return (NULL);
635 	}
636 	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
637 		return (NULL);
638 
639 	return (endptr);
640 }
641 
642 static int32_t
643 parse_physaddress(struct snmp_value *sv, char *val)
644 {
645 	char *endptr;
646 	int32_t i;
647 	uint32_t v;
648 	uint8_t	phys_addr[SNMP_PHYSADDR_OCTETS];
649 
650 	for (i = 0; i < 5; i++) {
651 		v = strtoul(val, &endptr, 16);
652 		if (v > 0xff) {
653 			warnx("Integer value %s not supported", val);
654 			return (-1);
655 		}
656 		if(*endptr != ':') {
657 			warnx("Failed reading octet - %s", val);
658 			return (-1);
659 		}
660 		phys_addr[i] = v;
661 		val = endptr + 1;
662 	}
663 
664 	/* The last one - don't check the ending char here. */
665 	v = strtoul(val, &endptr, 16);
666 	if (v > 0xff) {
667 		warnx("Integer value %s not supported", val);
668 		return (-1);
669 	}
670 	phys_addr[5] = v;
671 
672 	if ((sv->v.octetstring.octets = malloc(SNMP_PHYSADDR_OCTETS)) == NULL) {
673 		syslog(LOG_ERR,"malloc failed: %s", strerror(errno));
674 		return (-1);
675 	}
676 
677 	sv->v.octetstring.len = SNMP_PHYSADDR_OCTETS;
678 	memcpy(sv->v.octetstring.octets, phys_addr, SNMP_PHYSADDR_OCTETS);
679 	sv->syntax = SNMP_SYNTAX_OCTETSTRING;
680 	return (1);
681 }
682 
683 /**************************************************************
684  * NTPTimeStamp
685  **************************************************************
686  * NTP MIB, Revision 0.2, 7/25/97:
687  * NTPTimeStamp ::= TEXTUAL-CONVENTION
688  *    DISPLAY-HINT "4x.4x"
689  *    STATUS	current
690  *    DESCRIPTION
691  *	""
692  *    SYNTAX	OCTET STRING (SIZE(8))
693  */
694 static char *
695 snmp_oct2ntp_ts(uint32_t len, char *octets, char *buf)
696 {
697 	char *ptr;
698 	uint32_t i;
699 
700 	if (len != SNMP_NTP_TS_OCTETS || octets == NULL || buf == NULL)
701 		return (NULL);
702 
703 	buf[0]= '\0';
704 
705 	ptr = buf;
706 	i = octets[0] * 1000 + octets[1] * 100 + octets[2] * 10 + octets[3];
707 	ptr += sprintf(ptr, "%4.4d", i);
708 	i = octets[4] * 1000 + octets[5] * 100 + octets[6] * 10 + octets[7];
709 	ptr += sprintf(ptr, ".%4.4d", i);
710 
711 	return (buf);
712 }
713 
714 static char *
715 snmp_ntp_ts2asn_oid(char *str, struct asn_oid *oid)
716 {
717 	char *endptr, *ptr;
718 	uint32_t v, i, d;
719 	struct asn_oid suboid;
720 	int saved_errno;
721 
722 	if (snmp_suboid_append(oid, (asn_subid_t) SNMP_NTP_TS_OCTETS) < 0)
723 		return (NULL);
724 
725 	ptr = str;
726 	saved_errno = errno;
727 	v = strtoul(ptr, &endptr, 10);
728 	if (errno != 0 || (v / 1000) > 9) {
729 		warnx("Integer value %s not supported", str);
730 		errno = saved_errno;
731 		return (NULL);
732 	} else
733 		errno = saved_errno;
734 
735 	if (*endptr != '.') {
736 		warnx("Failed adding oid - %s",str);
737 		return (NULL);
738 	}
739 
740 	memset(&suboid, 0, sizeof(struct asn_oid));
741 	suboid.len = SNMP_NTP_TS_OCTETS;
742 
743 	for (i = 0, d = 1000; i < 4; i++) {
744 		suboid.subs[i] = v / d;
745 		v = v % d;
746 		d = d / 10;
747 	}
748 
749 	ptr = endptr + 1;
750 	saved_errno = errno;
751 	v = strtoul(ptr, &endptr, 10);
752 	if (errno != 0 || (v / 1000) > 9) {
753 		warnx("Integer value %s not supported", str);
754 		errno = saved_errno;
755 		return (NULL);
756 	} else
757 		errno = saved_errno;
758 
759 	for (i = 0, d = 1000; i < 4; i++) {
760 		suboid.subs[i + 4] = v / d;
761 		v = v % d;
762 		d = d / 10;
763 	}
764 
765 	asn_append_oid(oid, &suboid);
766 	return (endptr);
767 }
768 
769 static int32_t
770 parse_ntp_ts(struct snmp_value *sv, char *val)
771 {
772 	char *endptr;
773 	int32_t i, d, saved_errno;
774 	uint32_t v;
775 	uint8_t	ntp_ts[SNMP_NTP_TS_OCTETS];
776 
777 	saved_errno = errno;
778 	v = strtoul(val, &endptr, 10);
779 	if (errno != 0 || (v / 1000) > 9) {
780 		saved_errno = errno;
781 		warnx("Integer value %s not supported", val);
782 		return (-1);
783 	} else
784 		saved_errno = errno;
785 
786 	if (*endptr != '.') {
787 		warnx("Failed reading octet - %s", val);
788 		return (-1);
789 	}
790 
791 	for (i = 0, d = 1000; i < 4; i++) {
792 		ntp_ts[i] = v / d;
793 		v = v % d;
794 		d = d / 10;
795 	}
796 	val = endptr + 1;
797 
798 	saved_errno = errno;
799 	v = strtoul(val, &endptr, 10);
800 	if (errno != 0 || (v / 1000) > 9) {
801 		saved_errno = errno;
802 		warnx("Integer value %s not supported", val);
803 		return (-1);
804 	} else
805 		saved_errno = errno;
806 
807 	for (i = 0, d = 1000; i < 4; i++) {
808 		ntp_ts[i + 4] = v / d;
809 		v = v % d;
810 		d = d / 10;
811 	}
812 
813 	if ((sv->v.octetstring.octets = malloc(SNMP_NTP_TS_OCTETS)) == NULL) {
814 		syslog(LOG_ERR,"malloc failed: %s", strerror(errno));
815 		return (-1);
816 	}
817 
818 	sv->v.octetstring.len = SNMP_NTP_TS_OCTETS;
819 	memcpy(sv->v.octetstring.octets, ntp_ts, SNMP_NTP_TS_OCTETS);
820 	sv->syntax = SNMP_SYNTAX_OCTETSTRING;
821 	return (1);
822 }
823 
824 /**************************************************************
825  * BridgeId
826  **************************************************************
827  * BRIDGE-MIB, REVISION		"200509190000Z"
828  * BridgeId ::= TEXTUAL-CONVENTION
829  *    STATUS	current
830  *    DESCRIPTION
831  *	"The Bridge-Identifier, as used in the Spanning Tree
832  *	Protocol, to uniquely identify a bridge.  Its first two
833  *	octets (in network byte order) contain a priority value,
834  *	and its last 6 octets contain the MAC address used to
835  *	refer to a bridge in a unique fashion (typically, the
836  *	numerically smallest MAC address of all ports on the
837  *	bridge)."
838  *    SYNTAX	OCTET STRING (SIZE (8))
839  */
840 static char *
841 snmp_oct2bridgeid(uint32_t len, char *octets, char *buf)
842 {
843 	char *ptr;
844 	uint32_t i, priority;
845 
846 	if (len != SNMP_BRIDGEID_OCTETS || octets == NULL || buf == NULL)
847 		return (NULL);
848 
849 	buf[0]= '\0';
850 	ptr = buf;
851 
852 	priority = octets[0] << 8;
853 	priority += octets[1];
854 	if (priority > SNMP_MAX_BRIDGE_PRIORITY) {
855 		warnx("Invalid bridge priority %d", priority);
856 		return (NULL);
857 	} else
858 		ptr += sprintf(ptr, "%d.", octets[0]);
859 
860 	ptr += sprintf(ptr, "%2.2x", octets[2]);
861 
862 	for (i = 1; i < 6; i++)
863 		ptr += sprintf(ptr, ":%2.2x", octets[i + 2]);
864 
865 	return (buf);
866 }
867 
868 static char *
869 snmp_bridgeid2oct(char *str, struct asn_oid *oid)
870 {
871 	char *endptr, *ptr;
872 	uint32_t v, i;
873 	int32_t saved_errno;
874 
875 	if (snmp_suboid_append(oid, (asn_subid_t) SNMP_BRIDGEID_OCTETS) < 0)
876 		return (NULL);
877 
878 	ptr = str;
879 	/* Read the priority. */
880 	saved_errno = errno;
881 	v = strtoul(ptr, &endptr, 10);
882 	errno = 0;
883 
884 	if (v > SNMP_MAX_BRIDGE_PRIORITY || errno != 0 || *endptr != '.') {
885 		errno = saved_errno;
886 		warnx("Bad bridge priority value %d", v);
887 		return (NULL);
888 	}
889 
890 	if (snmp_suboid_append(oid, (asn_subid_t) (v & 0xff00)) < 0)
891 		return (NULL);
892 
893 	if (snmp_suboid_append(oid, (asn_subid_t) (v & 0xff)) < 0)
894 		return (NULL);
895 
896 	ptr = endptr + 1;
897 	for (i = 0; i < 5; i++) {
898 		saved_errno = errno;
899 		v = strtoul(ptr, &endptr, 16);
900 		errno = saved_errno;
901 		if (v > 0xff) {
902 			warnx("Integer value %s not supported", str);
903 			return (NULL);
904 		}
905 		if (*endptr != ':') {
906 			warnx("Failed adding oid - %s",str);
907 			return (NULL);
908 		}
909 		if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
910 			return (NULL);
911 		ptr = endptr + 1;
912 	}
913 
914 	/* The last one - don't check the ending char here. */
915 	saved_errno = errno;
916 	v = strtoul(ptr, &endptr, 16);
917 	errno = saved_errno;
918 	if (v > 0xff) {
919 		warnx("Integer value %s not supported", str);
920 		return (NULL);
921 	}
922 	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
923 		return (NULL);
924 
925 	return (endptr);
926 }
927 
928 static int32_t
929 parse_bridge_id(struct snmp_value *sv, char *string)
930 {
931 	char *ptr, *endptr;
932 	int32_t i, saved_errno;
933 	uint32_t v;
934 	uint8_t	bridge_id[SNMP_BRIDGEID_OCTETS];
935 
936 	ptr = string;
937 	/* Read the priority. */
938 	saved_errno = errno;
939 	errno = 0;
940 	v = strtoul(string, &endptr, 10);
941 	errno = saved_errno;
942 
943 	if (v > SNMP_MAX_BRIDGE_PRIORITY || errno != 0 || *endptr != '.') {
944 		errno = saved_errno;
945 		warnx("Bad bridge priority value %d", v);
946 		return (-1);
947 	}
948 
949 	bridge_id[0] = (v & 0xff00);
950 	bridge_id[1] = (v & 0xff);
951 
952 	string = endptr + 1;
953 
954 	for (i = 0; i < 5; i++) {
955 		v = strtoul(string, &endptr, 16);
956 		if (v > 0xff) {
957 			warnx("Integer value %s not supported", string);
958 			return (-1);
959 		}
960 		if(*endptr != ':') {
961 			warnx("Failed reading octet - %s", string);
962 			return (-1);
963 		}
964 		bridge_id[i + 2] = v;
965 		string = endptr + 1;
966 	}
967 
968 	/* The last one - don't check the ending char here. */
969 	v = strtoul(string, &endptr, 16);
970 	if (v > 0xff) {
971 		warnx("Integer value %s not supported", string);
972 		return (-1);
973 	}
974 	bridge_id[7] = v;
975 
976 	if ((sv->v.octetstring.octets = malloc(SNMP_BRIDGEID_OCTETS)) == NULL) {
977 		syslog(LOG_ERR,"malloc failed: %s", strerror(errno));
978 		return (-1);
979 	}
980 
981 	sv->v.octetstring.len = SNMP_BRIDGEID_OCTETS;
982 	memcpy(sv->v.octetstring.octets, bridge_id, SNMP_BRIDGEID_OCTETS);
983 	sv->syntax = SNMP_SYNTAX_OCTETSTRING;
984 	return (1);
985 }
986 
987 /**************************************************************
988  * BridgePortId
989  **************************************************************
990  * BEGEMOT-BRIDGE-MIB, LAST-UPDATED "200608100000Z"
991  * BridgePortId ::= TEXTUAL-CONVENTION
992  *    DISPLAY-HINT "1x.1x"
993  *    STATUS	current
994  *    DESCRIPTION
995  *	"A port identifier that contains a bridge port's STP priority
996  *	in the first octet and the port number in the second octet."
997  *    SYNTAX	OCTET STRING (SIZE(2))
998  */
999 static char *
1000 snmp_oct2bport_id(uint32_t len, char *octets, char *buf)
1001 {
1002 	char *ptr;
1003 
1004 	if (len != SNMP_BPORT_OCTETS || octets == NULL || buf == NULL)
1005 		return (NULL);
1006 
1007 	buf[0]= '\0';
1008 	ptr = buf;
1009 
1010 	ptr += sprintf(ptr, "%d.", octets[0]);
1011 	ptr += sprintf(ptr, "%d", octets[1]);
1012 
1013 	return (buf);
1014 }
1015 
1016 static char *
1017 snmp_bport_id2oct(char *str, struct asn_oid *oid)
1018 {
1019 	char *endptr, *ptr;
1020 	uint32_t v;
1021 	int saved_errno;
1022 
1023 	if (snmp_suboid_append(oid, (asn_subid_t) SNMP_BPORT_OCTETS) < 0)
1024 		return (NULL);
1025 
1026 	ptr = str;
1027 	/* Read the priority. */
1028 	saved_errno = errno;
1029 	v = strtoul(ptr, &endptr, 10);
1030 	errno = 0;
1031 
1032 	if (v > SNMP_MAX_BPORT_PRIORITY || errno != 0 || *endptr != '.') {
1033 		errno = saved_errno;
1034 		warnx("Bad bridge port priority value %d", v);
1035 		return (NULL);
1036 	}
1037 
1038 	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
1039 		return (NULL);
1040 
1041 	saved_errno = errno;
1042 	v = strtoul(ptr, &endptr, 16);
1043 	errno = saved_errno;
1044 
1045 	if (v > 0xff) {
1046 		warnx("Bad port number - %d", v);
1047 		return (NULL);
1048 	}
1049 
1050 	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
1051 		return (NULL);
1052 
1053 	return (endptr);
1054 }
1055 
1056 static int32_t
1057 parse_bport_id(struct snmp_value *value, char *string)
1058 {
1059 	char *ptr, *endptr;
1060 	int saved_errno;
1061 	uint32_t v;
1062 	uint8_t	bport_id[SNMP_BPORT_OCTETS];
1063 
1064 	ptr = string;
1065 	/* Read the priority. */
1066 	saved_errno = errno;
1067 	errno = 0;
1068 	v = strtoul(string, &endptr, 10);
1069 	errno = saved_errno;
1070 
1071 	if (v > SNMP_MAX_BPORT_PRIORITY || errno != 0 || *endptr != '.') {
1072 		errno = saved_errno;
1073 		warnx("Bad bridge port priority value %d", v);
1074 		return (-1);
1075 	}
1076 
1077 	bport_id[0] = v;
1078 
1079 	string = endptr + 1;
1080 	v = strtoul(string, &endptr, 16);
1081 	if (v > 0xff) {
1082 		warnx("Bad port number - %d", v);
1083 		return (-1);
1084 	}
1085 
1086 	bport_id[1] = v;
1087 
1088 	if ((value->v.octetstring.octets = malloc(SNMP_BPORT_OCTETS)) == NULL) {
1089 		syslog(LOG_ERR,"malloc failed: %s", strerror(errno));
1090 		return (-1);
1091 	}
1092 
1093 	value->v.octetstring.len = SNMP_BPORT_OCTETS;
1094 	memcpy(value->v.octetstring.octets, bport_id, SNMP_BPORT_OCTETS);
1095 	value->syntax = SNMP_SYNTAX_OCTETSTRING;
1096 	return (1);
1097 }
1098 /**************************************************************
1099  * InetAddress
1100  **************************************************************
1101  * INET-ADDRESS-MIB, REVISION     "200502040000Z"
1102  * InetAddress ::= TEXTUAL-CONVENTION
1103  *   STATUS      current
1104  *   DESCRIPTION
1105  *       "Denotes a generic Internet address.
1106  *
1107  *        An InetAddress value is always interpreted within the context
1108  *        of an InetAddressType value.  Every usage of the InetAddress
1109  *        textual convention is required to specify the InetAddressType
1110  *        object that provides the context.  It is suggested that the
1111  *        InetAddressType object be logically registered before the
1112  *        object(s) that use the InetAddress textual convention, if
1113  *        they appear in the same logical row.
1114  *
1115  *        The value of an InetAddress object must always be
1116  *        consistent with the value of the associated InetAddressType
1117  *        object.  Attempts to set an InetAddress object to a value
1118  *        inconsistent with the associated InetAddressType
1119  *        must fail with an inconsistentValue error.
1120  *
1121  *        When this textual convention is used as the syntax of an
1122  *        index object, there may be issues with the limit of 128
1123  *        sub-identifiers specified in SMIv2, STD 58.  In this case,
1124  *        the object definition MUST include a 'SIZE' clause to
1125  *        limit the number of potential instance sub-identifiers;
1126  *        otherwise the applicable constraints MUST be stated in
1127  *        the appropriate conceptual row DESCRIPTION clauses, or
1128  *        in the surrounding documentation if there is no single
1129  *        DESCRIPTION clause that is appropriate."
1130  *   SYNTAX       OCTET STRING (SIZE (0..255))
1131  **************************************************************
1132  * TODO: FIXME!!! syrinx: Since we do not support checking the
1133  * consistency of a varbinding based on the value of a previous
1134  * one, try to guess the type of address based on the
1135  * OctetString SIZE - 4 for IPv4, 16 for IPv6, others currently
1136  * not supported.
1137  */
1138 static char *
1139 snmp_oct2inetaddr(uint32_t len, char *octets, char *buf)
1140 {
1141 	int af;
1142 	void *ip;
1143 	struct in_addr	ipv4;
1144 	struct in6_addr	ipv6;
1145 
1146 	if (len > MAX_OCTSTRING_LEN || octets == NULL || buf == NULL)
1147 		return (NULL);
1148 
1149 	switch (len) {
1150 		/* XXX: FIXME - IPv4*/
1151 		case 4:
1152 			memcpy(&ipv4.s_addr, octets, sizeof(ipv4.s_addr));
1153 			af = AF_INET;
1154 			ip = &ipv4;
1155 			break;
1156 
1157 		/* XXX: FIXME - IPv4*/
1158 		case 16:
1159 			memcpy(ipv6.s6_addr, octets, sizeof(ipv6.s6_addr));
1160 			af = AF_INET6;
1161 			ip = &ipv6;
1162 			break;
1163 
1164 		default:
1165 			return (NULL);
1166 	}
1167 
1168 	if (inet_ntop(af, ip, buf, SNMP_INADDRS_STRSZ) == NULL) {
1169 		warnx("inet_ntop failed - %s", strerror(errno));
1170 		return (NULL);
1171 	}
1172 
1173 	return (buf);
1174 }
1175 
1176 static char *
1177 snmp_inetaddr2oct(char *str, struct asn_oid *oid)
1178 {
1179 	return (NULL);
1180 }
1181 
1182 static int32_t
1183 parse_inetaddr(struct snmp_value *value, char *string)
1184 {
1185 	return (-1);
1186 }
1187 
1188 /**************************************************************
1189  * SNMP BITS type - XXX: FIXME
1190  **************************************************************/
1191 static char *
1192 snmp_oct2bits(uint32_t len, char *octets, char *buf)
1193 {
1194 	int i, bits;
1195 	uint64_t value;
1196 
1197 	if (len > sizeof(value) || octets == NULL || buf == NULL)
1198 		return (NULL);
1199 
1200 	for (i = len, value = 0, bits = 0; i > 0; i--, bits += 8)
1201 		value += octets[i] << bits;
1202 
1203 	buf[0]= '\0';
1204 	sprintf(buf, "0x%llx.",(long long unsigned) value);
1205 
1206 	return (buf);
1207 }
1208 
1209 static char *
1210 snmp_bits2oct(char *str, struct asn_oid *oid)
1211 {
1212 	char *endptr;
1213 	int i, size, bits, saved_errno;
1214 	uint64_t v, mask = 0xFF00000000000000;
1215 
1216 	saved_errno = errno;
1217 	errno = 0;
1218 
1219 	v = strtoull(str, &endptr, 16);
1220 	if (errno != 0) {
1221 		warnx("Bad BITS value %s - %s", str, strerror(errno));
1222 		errno = saved_errno;
1223 		return (NULL);
1224 	}
1225 
1226 	bits = 8;
1227 	/* Determine length - up to 8 octets supported so far. */
1228 	for (size = sizeof(v); size > 0; size--) {
1229 		if ((v & mask) != 0)
1230 			break;
1231 		mask = mask >> bits;
1232 	}
1233 
1234 	if (size == 0)
1235 		size = 1;
1236 
1237 	if (snmp_suboid_append(oid, (asn_subid_t) size) < 0)
1238 		return (NULL);
1239 
1240 	for (i = 0, bits = 0; i < size; i++, bits += 8)
1241 		if (snmp_suboid_append(oid,
1242 		    (asn_subid_t)((v & mask) >> bits)) < 0)
1243 			return (NULL);
1244 
1245 	return (endptr);
1246 }
1247 
1248 static int32_t
1249 parse_bits(struct snmp_value *value, char *string)
1250 {
1251 	char *endptr;
1252 	int i, size, bits, saved_errno;
1253 	uint64_t v, mask = 0xFF00000000000000;
1254 
1255 	saved_errno = errno;
1256 	errno = 0;
1257 
1258 	v = strtoull(string, &endptr, 16);
1259 
1260 	if (errno != 0) {
1261 		warnx("Bad BITS value %s - %s", string, strerror(errno));
1262 		errno = saved_errno;
1263 		return (-1);
1264 	}
1265 
1266 	bits = 8;
1267 	/* Determine length - up to 8 octets supported so far. */
1268 	for (size = sizeof(v); size > 0; size--) {
1269 		if ((v & mask) != 0)
1270 			break;
1271 		mask = mask >> bits;
1272 	}
1273 
1274 	if (size == 0)
1275 		size = 1;
1276 
1277 	if ((value->v.octetstring.octets = malloc(size)) == NULL) {
1278 		syslog(LOG_ERR, "malloc failed: %s", strerror(errno));
1279 		return (-1);
1280 	}
1281 
1282 	value->v.octetstring.len = size;
1283 	for (i = 0, bits = 0; i < size; i++, bits += 8)
1284 		value->v.octetstring.octets[i] = (v & mask) >> bits;
1285 	value->syntax = SNMP_SYNTAX_OCTETSTRING;
1286 	return (1);
1287 }
1288