[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.14

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