]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptc.c
MFstable/11 r310901:
[FreeBSD/stable/10.git] / usr.sbin / bsnmpd / tools / libbsnmptools / bsnmptc.c
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         value->v.octetstring.len = len;
270
271         if((value->v.octetstring.octets = malloc(len)) == NULL) {
272                 syslog(LOG_ERR,"malloc failed: %s", strerror(errno));
273                 return (-1);
274         }
275
276         memcpy(value->v.octetstring.octets, val, len);
277         value->syntax = SNMP_SYNTAX_OCTETSTRING;
278
279         return (0);
280 }
281
282 /*************************************************************
283  * DateAndTime
284  *************************************************************
285  * rfc 2579 specification:
286  * DateAndTime ::= TEXTUAL-CONVENTION
287  *   DISPLAY-HINT "2d-1d-1d,1d:1d:1d.1d,1a1d:1d"
288  *   STATUS       current
289  *   DESCRIPTION
290  *      "A date-time specification.
291  *
292  *      field   octets  contents                range
293  *      -----   ------  --------                -----
294  *      1       1-2     year*                   0..65536
295  *      2       3       month                   1..12
296  *      3       4       day                     1..31
297  *      4       5       hour                    0..23
298  *      5       6       minutes                 0..59
299  *      6       7       seconds                 0..60
300  *                      (use 60 for leap-second)
301  *      7       8       deci-seconds            0..9
302  *      8       9       direction from UTC      '+' / '-'
303  *      9       10      hours from UTC*         0..13
304  *      10      11      minutes from UTC        0..59
305  *
306  *      * Notes:
307  *          - the value of year is in network-byte order
308  *          - daylight saving time in New Zealand is +13
309  *
310  *      For example, Tuesday May 26, 1992 at 1:30:15 PM EDT would be
311  *      displayed as:
312  *
313  *              1992-5-26,13:30:15.0,-4:0
314  */
315 static char *
316 snmp_octstr2date(uint32_t len, char *octets, char *buf)
317 {
318         int year;
319         char *ptr;
320
321         if (len != SNMP_DATETIME_OCTETS || octets == NULL || buf == NULL)
322                 return (NULL);
323
324         buf[0]= '\0';
325         year = (octets[0] << 8);
326         year += (octets[1]);
327
328         ptr = buf;
329         ptr += sprintf(ptr, "%4.4d-%.2d-%.2d, ", year, octets[2],octets[3]);
330         ptr += sprintf(ptr, "%2.2d:%2.2d:%2.2d.%.2d, ", octets[4],octets[5],
331             octets[6],octets[7]);
332         ptr += sprintf(ptr, "%c%.2d:%.2d", octets[8],octets[9],octets[10]);
333
334         return (buf);
335 }
336
337 static char *
338 snmp_date2asn_oid(char *str, struct asn_oid *oid)
339 {
340         char *endptr, *ptr;
341         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                 warnx("malloc() failed - %s", strerror(errno));
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                 warnx("inet_ntop failed - %s", strerror(errno));
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                 warnx("Bad BITS value %s - %s", str, strerror(errno));
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                 warnx("Bad BITS value %s - %s", string, strerror(errno));
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 }