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