[BACK]Return to smi.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / snmp

Annotation of src/usr.bin/snmp/smi.c, Revision 1.11

1.11    ! martijn     1: /*     $OpenBSD: smi.c,v 1.10 2020/08/03 14:45:54 martijn Exp $        */
1.1       martijn     2:
                      3: /*
                      4:  * Copyright (c) 2019 Martijn van Duren <martijn@openbsd.org>
                      5:  * Copyright (c) 2007, 2008 Reyk Floeter <reyk@openbsd.org>
                      6:  *
                      7:  * Permission to use, copy, modify, and distribute this software for any
                      8:  * purpose with or without fee is hereby granted, provided that the above
                      9:  * copyright notice and this permission notice appear in all copies.
                     10:  *
                     11:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
                     12:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     13:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
                     14:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     15:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
                     16:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
                     17:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
                     18:  */
                     19:
                     20: #include <sys/limits.h>
                     21: #include <sys/tree.h>
                     22: #include <sys/queue.h>
                     23:
                     24: #include <arpa/inet.h>
                     25:
                     26: #include <ctype.h>
1.10      martijn    27: #include <errno.h>
1.1       martijn    28: #include <stdlib.h>
                     29: #include <stdio.h>
                     30: #include <string.h>
                     31: #include <strings.h>
1.10      martijn    32: #include <wctype.h>
1.1       martijn    33:
                     34: #include "ber.h"
                     35: #include "mib.h"
                     36: #include "snmp.h"
                     37: #include "smi.h"
                     38:
                     39: #define MINIMUM(a, b)  (((a) < (b)) ? (a) : (b))
                     40:
1.10      martijn    41: char *smi_displayhint_os(struct textconv *, int, const char *, size_t, int);
                     42:
1.1       martijn    43: int smi_oid_cmp(struct oid *, struct oid *);
                     44: int smi_key_cmp(struct oid *, struct oid *);
1.10      martijn    45: int smi_textconv_cmp(struct textconv *, struct textconv *);
1.1       martijn    46: struct oid * smi_findkey(char *);
                     47:
                     48: RB_HEAD(oidtree, oid);
                     49: RB_PROTOTYPE(oidtree, oid, o_element, smi_oid_cmp)
                     50: struct oidtree smi_oidtree;
                     51:
                     52: RB_HEAD(keytree, oid);
                     53: RB_PROTOTYPE(keytree, oid, o_keyword, smi_key_cmp)
                     54: struct keytree smi_keytree;
                     55:
1.10      martijn    56: RB_HEAD(textconvtree, textconv);
                     57: RB_PROTOTYPE(textconvtree, textconv, tc_entry, smi_textconv_cmp);
                     58: struct textconvtree smi_tctree;
                     59:
1.1       martijn    60: int
                     61: smi_init(void)
                     62: {
                     63:        /* Initialize the Structure of Managed Information (SMI) */
                     64:        RB_INIT(&smi_oidtree);
                     65:        mib_init();
                     66:        return (0);
                     67: }
                     68:
                     69: void
1.10      martijn    70: smi_debug_elements(struct ber_element *root, int utf8)
1.1       martijn    71: {
                     72:        static int       indent = 0;
                     73:        char            *value;
                     74:        int              constructed;
                     75:
                     76:        /* calculate lengths */
1.6       tb         77:        ober_calc_len(root);
1.1       martijn    78:
                     79:        switch (root->be_encoding) {
                     80:        case BER_TYPE_SEQUENCE:
                     81:        case BER_TYPE_SET:
                     82:                constructed = root->be_encoding;
                     83:                break;
                     84:        default:
                     85:                constructed = 0;
                     86:                break;
                     87:        }
                     88:
                     89:        fprintf(stderr, "%*slen %lu ", indent, "", root->be_len);
                     90:        switch (root->be_class) {
                     91:        case BER_CLASS_UNIVERSAL:
                     92:                fprintf(stderr, "class: universal(%u) type: ", root->be_class);
                     93:                switch (root->be_type) {
                     94:                case BER_TYPE_EOC:
                     95:                        fprintf(stderr, "end-of-content");
                     96:                        break;
                     97:                case BER_TYPE_BOOLEAN:
                     98:                        fprintf(stderr, "boolean");
                     99:                        break;
                    100:                case BER_TYPE_INTEGER:
                    101:                        fprintf(stderr, "integer");
                    102:                        break;
                    103:                case BER_TYPE_BITSTRING:
                    104:                        fprintf(stderr, "bit-string");
                    105:                        break;
                    106:                case BER_TYPE_OCTETSTRING:
                    107:                        fprintf(stderr, "octet-string");
                    108:                        break;
                    109:                case BER_TYPE_NULL:
                    110:                        fprintf(stderr, "null");
                    111:                        break;
                    112:                case BER_TYPE_OBJECT:
                    113:                        fprintf(stderr, "object");
                    114:                        break;
                    115:                case BER_TYPE_ENUMERATED:
                    116:                        fprintf(stderr, "enumerated");
                    117:                        break;
                    118:                case BER_TYPE_SEQUENCE:
                    119:                        fprintf(stderr, "sequence");
                    120:                        break;
                    121:                case BER_TYPE_SET:
                    122:                        fprintf(stderr, "set");
                    123:                        break;
                    124:                }
                    125:                break;
                    126:        case BER_CLASS_APPLICATION:
                    127:                fprintf(stderr, "class: application(%u) type: ",
                    128:                    root->be_class);
                    129:                switch (root->be_type) {
                    130:                case SNMP_T_IPADDR:
                    131:                        fprintf(stderr, "ipaddr");
                    132:                        break;
                    133:                case SNMP_T_COUNTER32:
                    134:                        fprintf(stderr, "counter32");
                    135:                        break;
                    136:                case SNMP_T_GAUGE32:
                    137:                        fprintf(stderr, "gauge32");
                    138:                        break;
                    139:                case SNMP_T_TIMETICKS:
                    140:                        fprintf(stderr, "timeticks");
                    141:                        break;
                    142:                case SNMP_T_OPAQUE:
                    143:                        fprintf(stderr, "opaque");
                    144:                        break;
                    145:                case SNMP_T_COUNTER64:
                    146:                        fprintf(stderr, "counter64");
                    147:                        break;
                    148:                }
                    149:                break;
                    150:        case BER_CLASS_CONTEXT:
                    151:                fprintf(stderr, "class: context(%u) type: ",
                    152:                    root->be_class);
                    153:                switch (root->be_type) {
                    154:                case SNMP_C_GETREQ:
                    155:                        fprintf(stderr, "getreq");
                    156:                        break;
                    157:                case SNMP_C_GETNEXTREQ:
                    158:                        fprintf(stderr, "nextreq");
                    159:                        break;
                    160:                case SNMP_C_GETRESP:
                    161:                        fprintf(stderr, "getresp");
                    162:                        break;
                    163:                case SNMP_C_SETREQ:
                    164:                        fprintf(stderr, "setreq");
                    165:                        break;
                    166:                case SNMP_C_TRAP:
                    167:                        fprintf(stderr, "trap");
                    168:                        break;
                    169:                case SNMP_C_GETBULKREQ:
                    170:                        fprintf(stderr, "getbulkreq");
                    171:                        break;
                    172:                case SNMP_C_INFORMREQ:
                    173:                        fprintf(stderr, "informreq");
                    174:                        break;
                    175:                case SNMP_C_TRAPV2:
                    176:                        fprintf(stderr, "trapv2");
                    177:                        break;
                    178:                case SNMP_C_REPORT:
                    179:                        fprintf(stderr, "report");
                    180:                        break;
                    181:                }
                    182:                break;
                    183:        case BER_CLASS_PRIVATE:
                    184:                fprintf(stderr, "class: private(%u) type: ", root->be_class);
                    185:                break;
                    186:        default:
                    187:                fprintf(stderr, "class: <INVALID>(%u) type: ", root->be_class);
                    188:                break;
                    189:        }
                    190:        fprintf(stderr, "(%u) encoding %u ",
                    191:            root->be_type, root->be_encoding);
                    192:
1.10      martijn   193:        if ((value = smi_print_element(NULL, root, 1, smi_os_default,
                    194:            smi_oidl_numeric, utf8)) == NULL)
1.1       martijn   195:                goto invalid;
                    196:
                    197:        switch (root->be_encoding) {
                    198:        case BER_TYPE_BOOLEAN:
                    199:                fprintf(stderr, "%s", value);
                    200:                break;
                    201:        case BER_TYPE_INTEGER:
                    202:        case BER_TYPE_ENUMERATED:
                    203:                fprintf(stderr, "value %s", value);
                    204:                break;
                    205:        case BER_TYPE_BITSTRING:
                    206:                fprintf(stderr, "hexdump %s", value);
                    207:                break;
                    208:        case BER_TYPE_OBJECT:
                    209:                fprintf(stderr, "oid %s", value);
                    210:                break;
                    211:        case BER_TYPE_OCTETSTRING:
                    212:                if (root->be_class == BER_CLASS_APPLICATION &&
                    213:                    root->be_type == SNMP_T_IPADDR) {
                    214:                        fprintf(stderr, "addr %s", value);
                    215:                } else {
                    216:                        fprintf(stderr, "string %s", value);
                    217:                }
                    218:                break;
                    219:        case BER_TYPE_NULL:     /* no payload */
                    220:        case BER_TYPE_EOC:
                    221:        case BER_TYPE_SEQUENCE:
                    222:        case BER_TYPE_SET:
                    223:        default:
                    224:                fprintf(stderr, "%s", value);
                    225:                break;
                    226:        }
                    227:
                    228:  invalid:
                    229:        if (value == NULL)
                    230:                fprintf(stderr, "<INVALID>");
                    231:        else
                    232:                free(value);
                    233:        fprintf(stderr, "\n");
                    234:
                    235:        if (constructed)
                    236:                root->be_encoding = constructed;
                    237:
                    238:        if (constructed && root->be_sub) {
                    239:                indent += 2;
1.10      martijn   240:                smi_debug_elements(root->be_sub, utf8);
1.1       martijn   241:                indent -= 2;
                    242:        }
                    243:        if (root->be_next)
1.10      martijn   244:                smi_debug_elements(root->be_next, utf8);
1.1       martijn   245: }
                    246:
                    247: char *
1.10      martijn   248: smi_print_element(struct ber_oid *oid, struct ber_element *root, int print_hint,
                    249:     enum smi_output_string output_string, enum smi_oid_lookup lookup, int utf8)
1.1       martijn   250: {
                    251:        char            *str = NULL, *buf, *p;
1.10      martijn   252:        struct oid       okey;
                    253:        struct oid      *object = NULL;
                    254:        struct textconv  tckey;
1.5       jsg       255:        size_t           len, i, slen;
1.1       martijn   256:        long long        v, ticks;
                    257:        int              d;
1.4       martijn   258:        int              is_hex = 0, ret;
1.1       martijn   259:        struct ber_oid   o;
                    260:        char             strbuf[BUFSIZ];
                    261:        char            *hint;
                    262:        int              days, hours, min, sec, csec;
                    263:
1.10      martijn   264:        if (oid != NULL) {
                    265:                bcopy(oid, &(okey.o_id), sizeof(okey));
                    266:                do {
                    267:                        object = RB_FIND(oidtree, &smi_oidtree, &okey);
                    268:                        okey.o_id.bo_n--;
                    269:                } while (object == NULL && okey.o_id.bo_n > 0);
                    270:                if (object != NULL && object->o_textconv == NULL &&
                    271:                    object->o_tcname != NULL) {
                    272:                        tckey.tc_name = object->o_tcname;
                    273:                        object->o_textconv = RB_FIND(textconvtree, &smi_tctree,
                    274:                            &tckey);
                    275:                }
                    276:        }
                    277:
1.1       martijn   278:        switch (root->be_encoding) {
                    279:        case BER_TYPE_BOOLEAN:
1.6       tb        280:                if (ober_get_boolean(root, &d) == -1)
1.1       martijn   281:                        goto fail;
                    282:                if (print_hint) {
                    283:                        if (asprintf(&str, "INTEGER: %s(%d)",
                    284:                            d ? "true" : "false", d) == -1)
                    285:                                goto fail;
1.3       deraadt   286:                } else
1.1       martijn   287:                        if (asprintf(&str, "%s", d ? "true" : "false") == -1)
                    288:                                goto fail;
                    289:                break;
                    290:        case BER_TYPE_INTEGER:
                    291:        case BER_TYPE_ENUMERATED:
1.6       tb        292:                if (ober_get_integer(root, &v) == -1)
1.1       martijn   293:                        goto fail;
                    294:                if (root->be_class == BER_CLASS_APPLICATION &&
                    295:                    root->be_type == SNMP_T_TIMETICKS) {
                    296:                        ticks = v;
                    297:                        days = ticks / (60 * 60 * 24 * 100);
                    298:                        ticks %= (60 * 60 * 24 * 100);
                    299:                        hours = ticks / (60 * 60 * 100);
                    300:                        ticks %= (60 * 60 * 100);
                    301:                        min = ticks / (60 * 100);
                    302:                        ticks %= (60 * 100);
                    303:                        sec = ticks / 100;
                    304:                        ticks %= 100;
                    305:                        csec = ticks;
                    306:
                    307:                        if (print_hint) {
                    308:                                if (days == 0) {
                    309:                                        if (asprintf(&str,
                    310:                                            "Timeticks: (%lld) "
                    311:                                            "%d:%02d:%02d.%02d",
                    312:                                            v, hours, min, sec, csec) == -1)
                    313:                                                goto fail;
                    314:                                } else if (days == 1) {
                    315:                                        if (asprintf(&str,
                    316:                                            "Timeticks: (%lld) "
                    317:                                            "1 day %d:%02d:%02d.%02d",
                    318:                                            v, hours, min, sec, csec) == -1)
                    319:                                                goto fail;
                    320:                                } else {
                    321:                                        if (asprintf(&str,
                    322:                                            "Timeticks: (%lld) "
                    323:                                            "%d day %d:%02d:%02d.%02d",
                    324:                                            v, days, hours, min, sec, csec) ==
                    325:                                            -1)
                    326:                                                goto fail;
                    327:                                }
                    328:                        } else {
                    329:                                if (days == 0) {
                    330:                                        if (asprintf(&str, "%d:%02d:%02d.%02d",
                    331:                                            hours, min, sec, csec) == -1)
                    332:                                                goto fail;
                    333:                                } else if (days == 1) {
                    334:                                        if (asprintf(&str,
                    335:                                            "1 day %d:%02d:%02d.%02d",
                    336:                                            hours, min, sec, csec) == -1)
                    337:                                                goto fail;
                    338:                                } else {
                    339:                                        if (asprintf(&str,
                    340:                                            "%d day %d:%02d:%02d.%02d",
                    341:                                            days, hours, min, sec, csec) == -1)
                    342:                                                goto fail;
                    343:                                }
                    344:                        }
                    345:                        break;
                    346:                }
                    347:                hint = "INTEGER: ";
                    348:                if (root->be_class == BER_CLASS_APPLICATION) {
                    349:                        if (root->be_type == SNMP_T_COUNTER32)
                    350:                                hint = "Counter32: ";
                    351:                        else if (root->be_type == SNMP_T_GAUGE32)
                    352:                                hint = "Gauge32: ";
                    353:                        else if (root->be_type == SNMP_T_OPAQUE)
                    354:                                hint = "Opaque: ";
                    355:                        else if (root->be_type == SNMP_T_COUNTER64)
                    356:                                hint = "Counter64: ";
                    357:                }
1.3       deraadt   358:                if (asprintf(&str, "%s%lld", print_hint ? hint : "", v) == -1)
1.1       martijn   359:                        goto fail;
                    360:                break;
                    361:        case BER_TYPE_BITSTRING:
1.6       tb        362:                if (ober_get_bitstring(root, (void *)&buf, &len) == -1)
1.1       martijn   363:                        goto fail;
1.5       jsg       364:                slen = len * 2 + 1 + sizeof("BITS: ");
                    365:                if ((str = calloc(1, slen)) == NULL)
1.1       martijn   366:                        goto fail;
                    367:                p = str;
                    368:                if (print_hint) {
1.5       jsg       369:                        strlcpy(str, "BITS: ", slen);
1.1       martijn   370:                        p += sizeof("BITS: ");
                    371:                }
                    372:                for (i = 0; i < len; i++) {
                    373:                        snprintf(p, 3, "%02x", buf[i]);
                    374:                        p += 2;
                    375:                }
                    376:                break;
                    377:        case BER_TYPE_OBJECT:
1.6       tb        378:                if (ober_get_oid(root, &o) == -1)
1.1       martijn   379:                        goto fail;
                    380:                if (asprintf(&str, "%s%s",
                    381:                    print_hint ? "OID: " : "",
                    382:                    smi_oid2string(&o, strbuf, sizeof(strbuf), lookup)) == -1)
                    383:                        goto fail;
                    384:                break;
                    385:        case BER_TYPE_OCTETSTRING:
1.6       tb        386:                if (ober_get_string(root, &buf) == -1)
1.1       martijn   387:                        goto fail;
                    388:                if (root->be_class == BER_CLASS_APPLICATION &&
                    389:                    root->be_type == SNMP_T_IPADDR) {
                    390:                        if (asprintf(&str, "%s%s",
                    391:                            print_hint ? "IpAddress: " : "",
                    392:                            inet_ntoa(*(struct in_addr *)buf)) == -1)
                    393:                                goto fail;
1.7       martijn   394:                } else if (root->be_class == BER_CLASS_CONTEXT) {
                    395:                        if (root->be_type == SNMP_E_NOSUCHOBJECT)
                    396:                                str = strdup("No Such Object available on this "
                    397:                                    "agent at this OID");
                    398:                        else if (root->be_type == SNMP_E_NOSUCHINSTANCE)
                    399:                                str = strdup("No Such Instance currently "
                    400:                                    "exists at this OID");
                    401:                        else if (root->be_type == SNMP_E_ENDOFMIB)
                    402:                                str = strdup("No more variables left in this "
                    403:                                    "MIB View (It is past the end of the MIB "
                    404:                                    "tree)");
                    405:                        else
                    406:                                str = strdup("Unknown status at this OID");
1.2       deraadt   407:                } else {
1.10      martijn   408:                        if (object != NULL && object->o_textconv != NULL &&
                    409:                            object->o_textconv->tc_syntax == root->be_encoding)
                    410:                                return smi_displayhint_os(object->o_textconv,
                    411:                                    print_hint, buf, root->be_len, utf8);
1.1       martijn   412:                        for (i = 0; i < root->be_len; i++) {
                    413:                                if (!isprint(buf[i])) {
                    414:                                        if (output_string == smi_os_default)
                    415:                                                output_string = smi_os_hex;
                    416:                                        else if (output_string == smi_os_ascii)
                    417:                                                is_hex = 1;
                    418:                                        break;
                    419:                                }
                    420:                        }
                    421:                        /*
                    422:                         * hex is 3 * n (2 digits + n - 1 spaces + NUL-byte)
                    423:                         * ascii can be max (2 * n) + 2 quotes + NUL-byte
                    424:                         */
1.4       martijn   425:                        len = output_string == smi_os_hex ? 3 : 2;
                    426:                        p = str = reallocarray(NULL, root->be_len + 2, len);
                    427:                        if (p == NULL)
1.1       martijn   428:                                goto fail;
1.4       martijn   429:                        len *= root->be_len + 2;
                    430:                        if (is_hex) {
1.1       martijn   431:                                *str++ = '"';
1.4       martijn   432:                                len--;
                    433:                        }
1.1       martijn   434:                        for (i = 0; i < root->be_len; i++) {
                    435:                                switch (output_string) {
                    436:                                case smi_os_default:
                    437:                                        /* FALLTHROUGH */
                    438:                                case smi_os_ascii:
                    439:                                        /*
                    440:                                         * There's probably more edgecases here,
                    441:                                         * not fully investigated
                    442:                                         */
1.4       martijn   443:                                        if (len < 2)
                    444:                                                goto fail;
                    445:                                        if (is_hex && buf[i] == '\\') {
1.1       martijn   446:                                                *str++ = '\\';
1.4       martijn   447:                                                len--;
                    448:                                        }
1.1       martijn   449:                                        *str++ = isprint(buf[i]) ? buf[i] : '.';
1.4       martijn   450:                                        len--;
1.1       martijn   451:                                        break;
                    452:                                case smi_os_hex:
1.4       martijn   453:                                        ret = snprintf(str, len, "%s%02hhX",
1.1       martijn   454:                                            i == 0 ? "" :
                    455:                                            i % 16 == 0 ? "\n" : " ", buf[i]);
1.4       martijn   456:                                        if (ret == -1 || ret > (int) len)
                    457:                                                goto fail;
                    458:                                        len -= ret;
                    459:                                        str += ret;
1.1       martijn   460:                                        break;
                    461:                                }
                    462:                        }
1.4       martijn   463:                        if (is_hex) {
                    464:                                if (len < 2)
                    465:                                        goto fail;
1.1       martijn   466:                                *str++ = '"';
1.4       martijn   467:                                len--;
                    468:                        }
                    469:                        if (len == 0)
                    470:                                goto fail;
1.1       martijn   471:                        *str = '\0';
                    472:                        str = NULL;
                    473:                        if (asprintf(&str, "%s%s",
                    474:                            print_hint ?
                    475:                            output_string == smi_os_hex ? "Hex-STRING: " :
                    476:                            "STRING: " :
                    477:                            "", p) == -1) {
                    478:                                free(p);
                    479:                                goto fail;
                    480:                        }
                    481:                        free(p);
                    482:                }
                    483:                break;
                    484:        case BER_TYPE_NULL:     /* no payload */
                    485:        case BER_TYPE_EOC:
                    486:        case BER_TYPE_SEQUENCE:
                    487:        case BER_TYPE_SET:
                    488:        default:
                    489:                str = strdup("");
                    490:                break;
                    491:        }
                    492:
                    493:        return (str);
                    494:
                    495:  fail:
                    496:        free(str);
                    497:        return (NULL);
                    498: }
                    499:
                    500: int
                    501: smi_string2oid(const char *oidstr, struct ber_oid *o)
                    502: {
                    503:        char                    *sp, *p, str[BUFSIZ];
                    504:        const char              *errstr;
                    505:        struct oid              *oid;
                    506:        struct ber_oid           ko;
                    507:
                    508:        if (strlcpy(str, oidstr, sizeof(str)) >= sizeof(str))
                    509:                return (-1);
                    510:        bzero(o, sizeof(*o));
                    511:
                    512:        /*
                    513:         * Parse OID strings in the common form n.n.n or n-n-n.
1.6       tb        514:         * Based on ober_string2oid with additional support for symbolic names.
1.1       martijn   515:         */
                    516:        p = sp = str[0] == '.' ? str + 1 : str;
                    517:        for (; p != NULL; sp = p) {
                    518:                if ((p = strpbrk(p, ".-")) != NULL)
                    519:                        *p++ = '\0';
                    520:                if ((oid = smi_findkey(sp)) != NULL) {
                    521:                        bcopy(&oid->o_id, &ko, sizeof(ko));
1.6       tb        522:                        if (o->bo_n && ober_oid_cmp(o, &ko) != 2)
1.1       martijn   523:                                return (-1);
                    524:                        bcopy(&ko, o, sizeof(*o));
                    525:                        errstr = NULL;
                    526:                } else {
                    527:                        o->bo_id[o->bo_n++] =
                    528:                            strtonum(sp, 0, UINT_MAX, &errstr);
                    529:                }
                    530:                if (errstr || o->bo_n > BER_MAX_OID_LEN)
                    531:                        return (-1);
                    532:        }
                    533:
                    534:        return (0);
                    535: }
                    536:
                    537: unsigned int
                    538: smi_application(struct ber_element *elm)
                    539: {
                    540:        if (elm->be_class != BER_CLASS_APPLICATION)
                    541:                return (BER_TYPE_OCTETSTRING);
                    542:
                    543:        switch (elm->be_type) {
                    544:        case SNMP_T_IPADDR:
                    545:                return (BER_TYPE_OCTETSTRING);
                    546:        case SNMP_T_COUNTER32:
                    547:        case SNMP_T_GAUGE32:
                    548:        case SNMP_T_TIMETICKS:
                    549:        case SNMP_T_OPAQUE:
                    550:        case SNMP_T_COUNTER64:
                    551:                return (BER_TYPE_INTEGER);
                    552:        default:
                    553:                break;
                    554:        }
                    555:        return (BER_TYPE_OCTETSTRING);
                    556:
                    557: }
                    558:
                    559: char *
                    560: smi_oid2string(struct ber_oid *o, char *buf, size_t len,
                    561:     enum smi_oid_lookup lookup)
                    562: {
                    563:        char             str[256];
                    564:        struct oid      *value, key;
                    565:        size_t           i;
                    566:
                    567:        bzero(buf, len);
                    568:        bzero(&key, sizeof(key));
                    569:        bcopy(o, &key.o_id, sizeof(struct ber_oid));
                    570:
                    571:        for (i = 0; i < o->bo_n; i++) {
                    572:                key.o_oidlen = i + 1;
                    573:                if (lookup != smi_oidl_numeric &&
                    574:                    (value = RB_FIND(oidtree, &smi_oidtree, &key)) != NULL) {
                    575:                        snprintf(str, sizeof(str), "%s", value->o_name);
                    576:                        if (lookup == smi_oidl_short && i + 1 < o->bo_n) {
                    577:                                key.o_oidlen = i + 2;
                    578:                                if (RB_FIND(oidtree, &smi_oidtree, &key) != NULL)
                    579:                                        continue;
                    580:                        }
                    581:                } else
1.9       martijn   582:                        snprintf(str, sizeof(str), "%u", key.o_oid[i]);
1.1       martijn   583:                if (*buf != '\0' || i == 0)
                    584:                        strlcat(buf, ".", len);
                    585:                strlcat(buf, str, len);
                    586:        }
                    587:
                    588:        return (buf);
                    589: }
                    590:
                    591: void
                    592: smi_mibtree(struct oid *oids)
                    593: {
                    594:        struct oid      *oid, *decl;
                    595:        size_t           i;
                    596:
                    597:        for (i = 0; oids[i].o_oid[0] != 0; i++) {
                    598:                oid = &oids[i];
                    599:                if (oid->o_name != NULL) {
                    600:                        RB_INSERT(oidtree, &smi_oidtree, oid);
                    601:                        RB_INSERT(keytree, &smi_keytree, oid);
                    602:                        continue;
                    603:                }
                    604:                decl = RB_FIND(oidtree, &smi_oidtree, oid);
                    605:        }
                    606: }
                    607:
1.10      martijn   608: void
                    609: smi_textconvtree(struct textconv *textconvs)
                    610: {
                    611:        size_t           i = 0;
                    612:
                    613:        for (i = 0; textconvs[i].tc_name != NULL; i++)
                    614:                RB_INSERT(textconvtree, &smi_tctree, &(textconvs[i]));
                    615: }
                    616:
1.1       martijn   617: struct oid *
                    618: smi_findkey(char *name)
                    619: {
                    620:        struct oid      oid;
                    621:        if (name == NULL)
                    622:                return (NULL);
                    623:        oid.o_name = name;
                    624:        return (RB_FIND(keytree, &smi_keytree, &oid));
                    625: }
                    626:
                    627: struct oid *
1.8       martijn   628: smi_foreach(struct oid *oid)
1.1       martijn   629: {
                    630:        /*
                    631:         * Traverse the tree of MIBs with the option to check
                    632:         * for specific OID flags.
                    633:         */
1.8       martijn   634:        if (oid == NULL)
                    635:                return RB_MIN(oidtree, &smi_oidtree);
                    636:        return RB_NEXT(oidtree, &smi_oidtree, oid);
1.1       martijn   637: }
                    638:
1.10      martijn   639: #define REPLACEMENT "\357\277\275"
                    640: char *
                    641: smi_displayhint_os(struct textconv *tc, int print_hint, const char *src,
                    642:     size_t srclen, int utf8)
                    643: {
                    644:        size_t octetlength, i = 0, j = 0;
1.11    ! martijn   645:        size_t prefixlen;
1.10      martijn   646:        unsigned long ulval;
                    647:        int clen;
                    648:        char *displayformat;
1.11    ! martijn   649:        const char *prefix;
1.10      martijn   650:        char *rbuf, *dst;
                    651:        wchar_t wc;
                    652:
1.11    ! martijn   653:        prefix = print_hint ? "STRING: " : "";
        !           654:        prefixlen = strlen(prefix);
        !           655:
1.10      martijn   656:        errno = 0;
                    657:        ulval = strtoul(tc->tc_display_hint, &displayformat, 10);
                    658:        octetlength = ulval;
                    659:        if (!isdigit(tc->tc_display_hint[0]) ||
                    660:            (errno != 0 && (ulval == 0 || ulval == ULONG_MAX)) ||
                    661:            (unsigned long) octetlength != ulval) {
                    662:                errno = EINVAL;
                    663:                return NULL;
                    664:        }
                    665:
1.11    ! martijn   666:        if (displayformat[0] == 't' || displayformat[0] == 'a') {
        !           667:                if ((rbuf = malloc(prefixlen + octetlength + 1)) == NULL)
        !           668:                        return NULL;
        !           669:                (void)strlcpy(rbuf, prefix, prefixlen + octetlength + 1);
        !           670:                dst = rbuf + prefixlen;
1.10      martijn   671:                while (j < octetlength && i < srclen) {
                    672:                        clen = mbtowc(&wc, &(src[i]), srclen - i);
1.11    ! martijn   673:                        if (displayformat[0] == 'a' && clen > 1)
        !           674:                                clen = -1;
1.10      martijn   675:                        switch (clen) {
                    676:                        case 0:
                    677:                                dst[j++] = '.';
                    678:                                i++;
                    679:                                break;
                    680:                        case -1:
                    681:                                mbtowc(NULL, NULL, MB_CUR_MAX);
                    682:                                if (utf8) {
                    683:                                        if (octetlength - j <
                    684:                                            sizeof(REPLACEMENT) - 1) {
                    685:                                                dst[j] = '\0';
                    686:                                                return rbuf;
                    687:                                        }
                    688:                                        memcpy(&(dst[j]), REPLACEMENT,
                    689:                                            sizeof(REPLACEMENT) - 1);
                    690:                                        j += sizeof(REPLACEMENT) - 1;
                    691:                                } else
                    692:                                        dst[j++] = '?';
                    693:                                i++;
                    694:                                break;
                    695:                        default:
                    696:                                if (!iswprint(wc) || (!utf8 && clen > 1))
                    697:                                        dst[j++] = '.';
                    698:                                else if (octetlength - j < (size_t)clen) {
                    699:                                        dst[j] = '\0';
                    700:                                        return rbuf;
                    701:                                } else {
                    702:                                        memcpy(&(dst[j]), &(src[i]), clen);
                    703:                                        j += clen;
                    704:                                }
                    705:                                i += clen;
                    706:                                break;
                    707:                        }
                    708:                }
                    709:                dst[j] = '\0';
                    710:                return rbuf;
                    711:        }
                    712:        errno = EINVAL;
                    713:        return NULL;
                    714: }
                    715:
1.1       martijn   716: int
                    717: smi_oid_cmp(struct oid *a, struct oid *b)
                    718: {
                    719:        size_t   i;
                    720:
                    721:        for (i = 0; i < MINIMUM(a->o_oidlen, b->o_oidlen); i++) {
                    722:                if (a->o_oid[i] != b->o_oid[i])
                    723:                        return (a->o_oid[i] - b->o_oid[i]);
                    724:        }
                    725:
                    726:        return (a->o_oidlen - b->o_oidlen);
                    727: }
                    728:
                    729: int
                    730: smi_key_cmp(struct oid *a, struct oid *b)
                    731: {
                    732:        if (a->o_name == NULL || b->o_name == NULL)
                    733:                return (-1);
                    734:        return (strcasecmp(a->o_name, b->o_name));
                    735: }
                    736:
1.10      martijn   737: int
                    738: smi_textconv_cmp(struct textconv *a, struct textconv *b)
                    739: {
                    740:        return strcmp(a->tc_name, b->tc_name);
                    741: }
                    742:
1.1       martijn   743: RB_GENERATE(oidtree, oid, o_element, smi_oid_cmp)
                    744: RB_GENERATE(keytree, oid, o_keyword, smi_key_cmp)
1.10      martijn   745: RB_GENERATE(textconvtree, textconv, tc_entry, smi_textconv_cmp);