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