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