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
snmp_get_tc(char * str)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 *
snmp_oct2tc(enum snmp_tc tc,uint32_t len,char * octets)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 *
snmp_tc2oid(enum snmp_tc tc,char * str,struct asn_oid * oid)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
snmp_tc2oct(enum snmp_tc tc,struct snmp_value * value,char * string)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 *
snmp_oct2str(uint32_t len,char * octets,char * buf)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 *
snmp_str2asn_oid(char * str,struct asn_oid * oid)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
parse_octetstring(struct snmp_value * value,char * val)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 *
snmp_octstr2date(uint32_t len,char * octets,char * buf)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 *
snmp_date2asn_oid(char * str,struct asn_oid * oid)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
parse_dateandtime(struct snmp_value * sv,char * val)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 *
snmp_oct2physAddr(uint32_t len,char * octets,char * buf)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 *
snmp_addr2asn_oid(char * str,struct asn_oid * oid)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
parse_physaddress(struct snmp_value * sv,char * val)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 *
snmp_oct2ntp_ts(uint32_t len,char * octets,char * buf)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 *
snmp_ntp_ts2asn_oid(char * str,struct asn_oid * oid)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
parse_ntp_ts(struct snmp_value * sv,char * val)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 *
snmp_oct2bridgeid(uint32_t len,char * octets,char * buf)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 *
snmp_bridgeid2oct(char * str,struct asn_oid * oid)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
parse_bridge_id(struct snmp_value * sv,char * string)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 *
snmp_oct2bport_id(uint32_t len,char * octets,char * buf)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 *
snmp_bport_id2oct(char * str,struct asn_oid * oid)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
parse_bport_id(struct snmp_value * value,char * string)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 *
snmp_oct2inetaddr(uint32_t len,char * octets,char * buf)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 *
snmp_inetaddr2oct(char * str __unused,struct asn_oid * oid __unused)1187 snmp_inetaddr2oct(char *str __unused, struct asn_oid *oid __unused)
1188 {
1189 return (NULL);
1190 }
1191
1192 static int32_t
parse_inetaddr(struct snmp_value * value __unused,char * string __unused)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 *
snmp_oct2bits(uint32_t len,char * octets,char * buf)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 *
snmp_bits2oct(char * str,struct asn_oid * oid)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
parse_bits(struct snmp_value * value,char * string)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