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