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

Annotation of src/usr.bin/snmp/snmpc.c, Revision 1.7

1.7     ! deraadt     1: /*     $OpenBSD: snmpc.c,v 1.6 2019/08/13 12:28:03 martijn Exp $       */
1.1       martijn     2:
                      3: /*
                      4:  * Copyright (c) 2019 Martijn van Duren <martijn@openbsd.org>
                      5:  * Copyright (c) 2013 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/types.h>
                     22: #include <sys/socket.h>
                     23: #include <sys/un.h>
                     24:
                     25: #include <arpa/inet.h>
                     26:
                     27: #include <ber.h>
                     28: #include <err.h>
                     29: #include <errno.h>
                     30: #include <netdb.h>
                     31: #include <poll.h>
                     32: #include <stdio.h>
                     33: #include <stdlib.h>
                     34: #include <stdint.h>
                     35: #include <string.h>
                     36: #include <time.h>
                     37: #include <unistd.h>
                     38:
                     39: #include "smi.h"
                     40: #include "snmp.h"
                     41:
                     42: #define GETOPT_COMMON          "c:r:t:v:O:"
                     43:
                     44: int snmpc_get(int, char *[]);
                     45: int snmpc_walk(int, char *[]);
                     46: int snmpc_trap(int, char *[]);
                     47: int snmpc_mibtree(int, char *[]);
                     48: int snmpc_parseagent(char *, char *);
                     49: int snmpc_print(struct ber_element *);
                     50: __dead void snmpc_printerror(enum snmp_error, char *);
                     51: void usage(void);
                     52:
                     53: struct snmp_app {
                     54:        const char *name;
                     55:        const int usecommonopt;
                     56:        const char *optstring;
                     57:        const char *usage;
1.2       deraadt    58:        int (*exec)(int, char *[]);
1.1       martijn    59: };
                     60:
                     61: struct snmp_app snmp_apps[] = {
1.2       deraadt    62:        { "get", 1, NULL, "agent oid ...", snmpc_get },
                     63:        { "getnext", 1, NULL, "agent oid ...", snmpc_get },
1.7     ! deraadt    64:        { "walk", 1, "C:", "[-C cIipt] [-C E endoid] agent [oid]", snmpc_walk },
1.2       deraadt    65:        { "bulkget", 1, "C:", "[-C n<nonrep>r<maxrep>] agent oid ...", snmpc_get },
                     66:        { "bulkwalk", 1, "C:", "[-C cipn<nonrep>r<maxrep>] agent [oid]", snmpc_walk },
                     67:        { "trap", 1, NULL, "agent uptime oid [oid type value] ...", snmpc_trap },
                     68:        { "mibtree", 0, "O:", "[-O fnS]", snmpc_mibtree }
1.1       martijn    69: };
                     70: struct snmp_app *snmp_app = NULL;
                     71:
                     72: char *community = "public";
                     73: char *mib = "mib_2";
                     74: int retries = 5;
                     75: int timeout = 1;
                     76: int version = SNMP_V2C;
                     77: int print_equals = 1;
                     78: int print_varbind_only = 0;
                     79: int print_summary = 0;
                     80: int print_time = 0;
                     81: int walk_check_increase = 1;
                     82: int walk_fallback_oid = 1;
                     83: int walk_include_oid = 0;
                     84: int smi_print_hint = 1;
                     85: int non_repeaters = 0;
                     86: int max_repetitions = 10;
                     87: struct ber_oid walk_end = {{0}, 0};
                     88: enum smi_oid_lookup oid_lookup = smi_oidl_short;
                     89: enum smi_output_string output_string = smi_os_default;
                     90:
                     91: int
                     92: main(int argc, char *argv[])
                     93: {
                     94:        char optstr[BUFSIZ];
                     95:        const char *errstr;
                     96:        char *strtolp;
                     97:        int ch;
                     98:        size_t i;
                     99:
                    100:        if (pledge("stdio inet dns", NULL) == -1)
                    101:                err(1, "pledge");
1.2       deraadt   102:
1.1       martijn   103:        if (argc <= 1)
                    104:                usage();
                    105:
                    106:        for (i = 0; i < sizeof(snmp_apps)/sizeof(*snmp_apps); i++) {
                    107:                if (strcmp(snmp_apps[i].name, argv[1]) == 0) {
                    108:                        snmp_app = &snmp_apps[i];
                    109:                        if (snmp_app->optstring != NULL) {
                    110:                                if (strlcpy(optstr, snmp_app->optstring,
                    111:                                    sizeof(optstr)) > sizeof(optstr))
                    112:                                        errx(1, "strlcat");
                    113:                        }
                    114:                        break;
                    115:                }
                    116:        }
                    117:        if (snmp_app == NULL)
                    118:                usage();
                    119:
                    120:        if (snmp_app->usecommonopt) {
                    121:                if (strlcat(optstr, GETOPT_COMMON, sizeof(optstr)) >
                    122:                    sizeof(optstr))
                    123:                        errx(1, "strlcpy");
                    124:        }
                    125:
                    126:        argc--;
                    127:        argv++;
                    128:
                    129:        smi_init();
                    130:
                    131:        while ((ch = getopt(argc, argv, optstr)) != -1) {
                    132:                switch (ch) {
                    133:                case 'c':
                    134:                        community = optarg;
                    135:                        break;
                    136:                case 'r':
                    137:                        if ((retries = strtonum(optarg, 0, INT_MAX,
                    138:                            &errstr)) == 0) {
                    139:                                if (errstr != NULL)
                    140:                                        errx(1, "-r: %s argument", errstr);
                    141:                        }
                    142:                        break;
                    143:                case 't':
                    144:                        if ((timeout = strtonum(optarg, 1, INT_MAX,
                    145:                            &errstr)) == 0) {
                    146:                                if (errstr != NULL)
                    147:                                        errx(1, "-t: %s argument", errstr);
                    148:                        }
                    149:                        break;
                    150:                case 'v':
                    151:                        if (strcmp(optarg, "1") == 0)
                    152:                                version = SNMP_V1;
                    153:                        else if (strcmp(optarg, "2c") == 0)
                    154:                                version = SNMP_V2C;
                    155:                        else
                    156:                                errc(1, EINVAL, "-v");
                    157:                        break;
                    158:                case 'C':
                    159:                        for (i = 0; i < strlen(optarg); i++) {
                    160:                                switch (optarg[i]) {
                    161:                                case 'c':
                    162:                                        if (strcmp(snmp_app->name, "walk") &&
                    163:                                            strcmp(snmp_app->name, "bulkwalk"))
                    164:                                                usage();
                    165:                                        walk_check_increase = 0;
                    166:                                        break;
                    167:                                case 'i':
                    168:                                        if (strcmp(snmp_app->name, "walk") &&
                    169:                                            strcmp(snmp_app->name, "bulkwalk"))
                    170:                                                usage();
                    171:                                        walk_include_oid = 1;
                    172:                                        break;
                    173:                                case 'n':
                    174:                                        if (strcmp(snmp_app->name, "bulkget") &&
                    175:                                            strcmp(snmp_app->name, "bulkwalk"))
                    176:                                                usage();
                    177:                                        errno = 0;
                    178:                                        non_repeaters = strtol(&optarg[i + 1],
                    179:                                            &strtolp, 10);
                    180:                                        if (non_repeaters < 0 ||
                    181:                                            errno == ERANGE) {
                    182:                                                if (non_repeaters < 0)
                    183:                                                        errx(1, "%s%s",
                    184:                                                            "-Cn: too small ",
                    185:                                                            "argument");
                    186:                                                else
                    187:                                                        errx(1, "%s%s",
                    188:                                                            "-Cn: too large",
                    189:                                                            "argument");
                    190:                                        } else if (&optarg[i + 1] == strtolp)
                    191:                                                errx(1, "-Cn invalid argument");
                    192:                                        i = strtolp - optarg - 1;
                    193:                                        break;
                    194:                                case 'p':
                    195:                                        if (strcmp(snmp_app->name, "walk") &&
                    196:                                            strcmp(snmp_app->name, "bulkwalk"))
                    197:                                                usage();
                    198:                                        print_summary = 1;
                    199:                                        break;
                    200:                                case 'r':
                    201:                                        if (strcmp(snmp_app->name, "bulkget") &&
                    202:                                            strcmp(snmp_app->name, "bulkwalk"))
                    203:                                                usage();
                    204:                                        errno = 0;
                    205:                                        max_repetitions = strtol(&optarg[i + 1],
                    206:                                            &strtolp, 10);
                    207:                                        if (max_repetitions < 0 ||
                    208:                                            errno == ERANGE) {
                    209:                                                if (max_repetitions < 0)
                    210:                                                        errx(1, "%s%s",
                    211:                                                            "-Cr: too small ",
                    212:                                                            "argument");
                    213:                                                else
                    214:                                                        errx(1, "%s%s",
                    215:                                                            "-Cr: too large",
                    216:                                                            "argument");
                    217:                                        } else if (&optarg[i + 1] == strtolp)
                    218:                                                errx(1, "-Cr invalid argument");
                    219:                                        i = strtolp - optarg - 1;
                    220:                                        break;
                    221:                                case 't':
                    222:                                        if (strcmp(snmp_app->name, "walk"))
                    223:                                                usage();
                    224:                                        print_time = 1;
                    225:                                        break;
                    226:                                case 'E':
                    227:                                        if (strcmp(snmp_app->name, "walk"))
                    228:                                                usage();
                    229:                                        if (smi_string2oid(argv[optind],
                    230:                                            &walk_end) != 0)
                    231:                                                errx(1, "%s: %s",
                    232:                                                    "Unknown Object Identifier",
                    233:                                                    argv[optind]);
                    234:                                        optind++;
                    235:                                        continue;
                    236:                                case 'I':
                    237:                                        if (strcmp(snmp_app->name, "walk"))
                    238:                                                usage();
                    239:                                        walk_fallback_oid = 0;
                    240:                                        break;
                    241:                                default:
                    242:                                        usage();
                    243:                                }
                    244:                                if (optarg[i] == 'E')
                    245:                                        break;
                    246:                        }
                    247:                        break;
                    248:                case 'O':
                    249:                        for (i = 0; i < strlen(optarg); i++) {
                    250:                                if (strcmp(snmp_app->name, "mibtree") == 0 &&
                    251:                                    optarg[i] != 'f' && optarg[i] != 'n' &&
                    252:                                    optarg[i] != 'S')
                    253:                                                usage();
                    254:                                switch (optarg[i]) {
                    255:                                case 'a':
                    256:                                        output_string = smi_os_ascii;
                    257:                                        break;
                    258:                                case 'f':
                    259:                                        oid_lookup = smi_oidl_full;
                    260:                                        break;
                    261:                                case 'n':
                    262:                                        oid_lookup = smi_oidl_numeric;
                    263:                                        break;
                    264:                                case 'q':
                    265:                                        print_equals = 0;
                    266:                                        smi_print_hint = 0;
                    267:                                        break;
                    268:                                case 'v':
1.2       deraadt   269:                                        print_varbind_only = 1;
1.1       martijn   270:                                        break;
                    271:                                case 'x':
                    272:                                        output_string = smi_os_hex;
                    273:                                        break;
                    274:                                case 'S':
                    275:                                        oid_lookup = smi_oidl_short;
                    276:                                        break;
                    277:                                case 'Q':
                    278:                                        smi_print_hint = 0;
                    279:                                        break;
                    280:                                default:
                    281:                                        usage();
                    282:                                }
                    283:                        }
                    284:                        break;
                    285:                default:
                    286:                        usage();
                    287:                }
                    288:        }
                    289:        argc -= optind;
                    290:        argv += optind;
                    291:
                    292:        return snmp_app->exec(argc, argv);
                    293: }
                    294:
                    295: int
                    296: snmpc_get(int argc, char *argv[])
                    297: {
                    298:        struct ber_oid *oid;
                    299:        struct ber_element *pdu, *varbind;
                    300:        struct snmp_agent *agent;
                    301:        int errorstatus, errorindex;
                    302:        int i;
                    303:
                    304:        if (argc < 2)
                    305:                usage();
                    306:
                    307:        agent = snmp_connect_v12(snmpc_parseagent(argv[0], "161"), version,
                    308:            community);
                    309:        if (agent == NULL)
                    310:                err(1, "%s", snmp_app->name);
                    311:        agent->timeout = timeout;
                    312:        agent->retries = retries;
                    313:
                    314:        if (pledge("stdio", NULL) == -1)
                    315:                err(1, "pledge");
                    316:        argc--;
                    317:        argv++;
                    318:
                    319:        oid = reallocarray(NULL, argc, sizeof(*oid));
1.3       deraadt   320:        if (oid == NULL)
                    321:                err(1, "malloc");
1.1       martijn   322:        for (i = 0; i < argc; i++) {
                    323:                if (smi_string2oid(argv[i], &oid[i]) == -1)
                    324:                        errx(1, "%s: Unknown object identifier", argv[0]);
                    325:        }
                    326:        if (strcmp(snmp_app->name, "getnext") == 0) {
                    327:                if ((pdu = snmp_getnext(agent, oid, argc)) == NULL)
                    328:                        err(1, "getnext");
                    329:        } else if (strcmp(snmp_app->name, "bulkget") == 0) {
                    330:                if (version < SNMP_V2C)
                    331:                        errx(1, "Cannot send V2 PDU on V1 session");
                    332:                if (non_repeaters > argc)
                    333:                        errx(1, "need more objects than -Cn<num>");
                    334:                if ((pdu = snmp_getbulk(agent, oid, argc, non_repeaters,
                    335:                    max_repetitions)) == NULL)
                    336:                        err(1, "bulkget");
                    337:        } else {
                    338:                if ((pdu = snmp_get(agent, oid, argc)) == NULL)
                    339:                        err(1, "get");
                    340:        }
                    341:
                    342:        (void) ber_scanf_elements(pdu, "{Sdd{e", &errorstatus, &errorindex,
                    343:            &varbind);
                    344:        if (errorstatus != 0)
                    345:                snmpc_printerror((enum snmp_error) errorstatus,
1.6       martijn   346:                    argv[errorindex - 1]);
1.1       martijn   347:
                    348:        for (; varbind != NULL; varbind = varbind->be_next) {
                    349:                if (!snmpc_print(varbind))
                    350:                        err(1, "Can't print response");
                    351:        }
                    352:        ber_free_elements(pdu);
                    353:        snmp_free_agent(agent);
                    354:        return 0;
                    355: }
                    356:
                    357: int
                    358: snmpc_walk(int argc, char *argv[])
                    359: {
                    360:        struct ber_oid oid, loid, noid;
                    361:        struct ber_element *pdu, *varbind, *value;
                    362:        struct timespec start, finish;
                    363:        struct snmp_agent *agent;
                    364:        const char *oids;
                    365:        char oidstr[SNMP_MAX_OID_STRLEN];
                    366:        int n = 0, prev_cmp;
                    367:        int errorstatus, errorindex;
                    368:
                    369:        if (strcmp(snmp_app->name, "bulkwalk") == 0 && version < SNMP_V2C)
                    370:                errx(1, "Cannot send V2 PDU on V1 session");
                    371:        if (argc < 1 || argc > 2)
                    372:                usage();
                    373:        oids = argc == 1 ? mib : argv[1];
                    374:
                    375:        agent = snmp_connect_v12(snmpc_parseagent(argv[0], "161"), version, community);
                    376:        if (agent == NULL)
                    377:                err(1, "%s", snmp_app->name);
                    378:        agent->timeout = timeout;
                    379:        agent->retries = retries;
                    380:        if (pledge("stdio", NULL) == -1)
                    381:                err(1, "pledge");
                    382:
                    383:        if (smi_string2oid(oids, &oid) == -1)
                    384:                errx(1, "%s: Unknown object identifier", oids);
                    385:        bcopy(&oid, &noid, sizeof(noid));
                    386:        if (print_time)
                    387:                clock_gettime(CLOCK_MONOTONIC, &start);
                    388:
                    389:        if (walk_include_oid) {
                    390:                if ((pdu = snmp_get(agent, &oid, 1)) == NULL)
                    391:                        err(1, "%s", snmp_app->name);
                    392:
                    393:                (void) ber_scanf_elements(pdu, "{Sdd{e", &errorstatus,
                    394:                    &errorindex, &varbind);
                    395:                if (errorstatus != 0)
                    396:                        snmpc_printerror((enum snmp_error) errorstatus,
1.6       martijn   397:                            argv[errorindex - 1]);
1.1       martijn   398:
                    399:                if (!snmpc_print(varbind))
                    400:                        err(1, "Can't print response");
                    401:                ber_free_element(pdu);
                    402:                n++;
                    403:        }
                    404:        while (1) {
                    405:                bcopy(&noid, &loid, sizeof(loid));
                    406:                if (strcmp(snmp_app->name, "bulkwalk") == 0) {
                    407:                        if ((pdu = snmp_getbulk(agent, &noid, 1,
                    408:                            non_repeaters, max_repetitions)) == NULL)
                    409:                                err(1, "bulkwalk");
                    410:                } else {
                    411:                        if ((pdu = snmp_getnext(agent, &noid, 1)) == NULL)
                    412:                                err(1, "walk");
                    413:                }
                    414:
                    415:                (void) ber_scanf_elements(pdu, "{Sdd{e", &errorstatus,
                    416:                    &errorindex, &varbind);
                    417:                if (errorstatus != 0) {
                    418:                        smi_oid2string(&noid, oidstr, sizeof(oidstr),
                    419:                            oid_lookup);
                    420:                        snmpc_printerror((enum snmp_error) errorstatus, oidstr);
                    421:                }
                    422:
1.2       deraadt   423:                for (; varbind != NULL; varbind = varbind->be_next) {
1.1       martijn   424:                        (void) ber_scanf_elements(varbind, "{oe}", &noid,
                    425:                            &value);
                    426:                        if (value->be_class == BER_CLASS_CONTEXT &&
                    427:                            value->be_type == BER_TYPE_EOC)
                    428:                                break;
                    429:                        prev_cmp = ber_oid_cmp(&loid, &noid);
                    430:                        if (walk_check_increase && prev_cmp == -1)
                    431:                                errx(1, "OID not increasing");
                    432:                        if (prev_cmp == 0 || ber_oid_cmp(&oid, &noid) != 2)
                    433:                                break;
                    434:                        if (walk_end.bo_n != 0 &&
                    435:                            ber_oid_cmp(&walk_end, &noid) != -1)
                    436:                                break;
                    437:
                    438:                        if (!snmpc_print(varbind))
                    439:                                err(1, "Can't print response");
                    440:                        n++;
                    441:                }
                    442:                ber_free_elements(pdu);
                    443:                if (varbind != NULL)
                    444:                        break;
                    445:        }
                    446:        if (walk_fallback_oid && n == 0) {
                    447:                if ((pdu = snmp_get(agent, &oid, 1)) == NULL)
                    448:                        err(1, "%s", snmp_app->name);
                    449:
                    450:                (void) ber_scanf_elements(pdu, "{Sdd{e", &errorstatus,
                    451:                    &errorindex, &varbind);
                    452:                if (errorstatus != 0)
                    453:                        snmpc_printerror((enum snmp_error) errorstatus,
1.6       martijn   454:                            argv[errorindex - 1]);
1.1       martijn   455:
                    456:                if (!snmpc_print(varbind))
                    457:                        err(1, "Can't print response");
                    458:                ber_free_element(pdu);
                    459:                n++;
                    460:        }
                    461:        if (print_time)
                    462:                clock_gettime(CLOCK_MONOTONIC, &finish);
                    463:        if (print_summary)
                    464:                printf("Variables found: %d\n", n);
                    465:        if (print_time) {
                    466:                if ((finish.tv_nsec -= start.tv_nsec) < 0) {
                    467:                        finish.tv_sec -= 1;
                    468:                        finish.tv_nsec += 1000000000;
                    469:                }
                    470:                finish.tv_sec -= start.tv_sec;
                    471:                fprintf(stderr, "Total traversal time: %lld.%09ld seconds\n",
                    472:                    finish.tv_sec, finish.tv_nsec);
                    473:        }
                    474:        snmp_free_agent(agent);
                    475:        return 0;
                    476: }
                    477:
                    478: int
                    479: snmpc_trap(int argc, char *argv[])
                    480: {
                    481:        struct snmp_agent *agent;
                    482:        struct timespec ts;
                    483:        struct ber_oid trapoid, oid, oidval;
                    484:        struct in_addr addr4;
                    485:        char *addr = (char *)&addr4;
                    486:        char *str = NULL, *tmpstr, *endstr;
                    487:        const char *errstr = NULL;
                    488:        struct ber_element *varbind = NULL, *pdu = NULL;
                    489:        long long lval;
                    490:        int i, ret;
                    491:        size_t strl, byte;
                    492:
                    493:        if (argc < 3 || argc % 3 != 0)
                    494:                usage();
                    495:        if (version == SNMP_V1)
                    496:                errx(1, "trap is not supported for snmp v1");
                    497:
                    498:        agent = snmp_connect_v12(snmpc_parseagent(argv[0], "162"),
                    499:            version, community);
                    500:        if (agent == NULL)
                    501:                err(1, "%s", snmp_app->name);
                    502:
                    503:        if (pledge("stdio", NULL) == -1)
                    504:                err(1, "pledge");
                    505:
                    506:        if (argv[1][0] == '\0') {
                    507:                if (clock_gettime(CLOCK_UPTIME, &ts) == -1)
                    508:                        err(1, "clock_gettime");
                    509:        } else {
                    510:                lval = strtonum(argv[1], 0, LLONG_MAX, &errstr);
                    511:                if (errstr != NULL)
                    512:                        errx(1, "Bad value notation (%s)", argv[1]);
                    513:                ts.tv_sec = lval / 100;
                    514:                ts.tv_nsec = (lval % 100) * 10000000;
                    515:        }
                    516:        if (smi_string2oid(argv[2], &trapoid) == -1)
                    517:                errx(1, "Invalid oid: %s\n", argv[2]);
                    518:
                    519:        argc -= 3;
                    520:        argv += 3;
                    521:        for (i = 0; i < argc; i += 3) {
                    522:                if (smi_string2oid(argv[i], &oid) == -1)
                    523:                        errx(1, "Invalid oid: %s\n", argv[i]);
                    524:                switch (argv[i + 1][0]) {
                    525:                case 'a':
                    526:                        ret = inet_pton(AF_INET, argv[i + 2], &addr4);
                    527:                        if (ret == -1)
                    528:                                err(1, "inet_pton");
                    529:                        if (ret == 0)
                    530:                                errx(1, "%s: Bad value notation (%s)", argv[i],
                    531:                                    argv[i + 2]);
                    532:                        if ((varbind = ber_printf_elements(varbind, "{Oxt}",
                    533:                            &oid, addr, sizeof(addr4), BER_CLASS_APPLICATION,
                    534:                            SNMP_T_IPADDR)) == NULL)
                    535:                                err(1, "ber_printf_elements");
                    536:                        break;
                    537:                case 'b':
                    538:                        tmpstr = argv[i + 2];
                    539:                        strl = 0;
                    540:                        do {
                    541:                                lval = strtoll(tmpstr, &endstr, 10);
                    542:                                if (endstr[0] != ' ' && endstr[0] != '\t' &&
                    543:                                    endstr[0] != ',' && endstr[0] != '\0')
                    544:                                        errx(1, "%s: Bad value notation (%s)",
                    545:                                            argv[i], argv[i + 2]);
                    546:                                if (tmpstr == endstr) {
                    547:                                        tmpstr++;
                    548:                                        continue;
                    549:                                }
                    550:                                if (lval < 0)
                    551:                                        errx(1, "%s: Bad value notation (%s)",
                    552:                                            argv[i], argv[i + 2]);
                    553:                                byte = lval / 8;
                    554:                                if (byte >= strl) {
                    555:                                        if ((str = recallocarray(str, strl,
                    556:                                            byte + 1, 1)) == NULL)
1.5       martijn   557:                                                err(1, "malloc");
1.1       martijn   558:                                        strl = byte + 1;
                    559:                                }
                    560:                                str[byte] |= 0x80 >> (lval % 8);
                    561:                                tmpstr = endstr + 1;
                    562:                        } while (endstr[0] != '\0');
                    563:                        /*
                    564:                         * RFC3416 Section 2.5
                    565:                         * A BITS value is encoded as an OCTET STRING
                    566:                         */
                    567:                        goto pastestring;
                    568:                case 'c':
                    569:                        lval = strtonum(argv[i + 2], INT32_MIN, INT32_MAX,
                    570:                            &errstr);
                    571:                        if (errstr != NULL)
                    572:                                errx(1, "%s: Bad value notation (%s)", argv[i],
                    573:                                    argv[i + 2]);
                    574:                        if ((varbind = ber_printf_elements(varbind, "{Oit}",
                    575:                            &oid, lval, BER_CLASS_APPLICATION,
                    576:                            SNMP_T_COUNTER32)) == NULL)
                    577:                                err(1, "ber_printf_elements");
                    578:                        break;
                    579:                case 'd':
                    580:                        /* String always shrinks */
                    581:                        if ((str = malloc(strlen(argv[i + 2]))) == NULL)
1.5       martijn   582:                                err(1, "malloc");
1.1       martijn   583:                        tmpstr = argv[i + 2];
                    584:                        strl = 0;
                    585:                        do {
                    586:                                lval = strtoll(tmpstr, &endstr, 10);
                    587:                                if (endstr[0] != ' ' && endstr[0] != '\t' &&
                    588:                                    endstr[0] != '\0')
                    589:                                        errx(1, "%s: Bad value notation (%s)",
                    590:                                            argv[i], argv[i + 2]);
                    591:                                if (tmpstr == endstr) {
                    592:                                        tmpstr++;
                    593:                                        continue;
                    594:                                }
                    595:                                if (lval < 0 || lval > 0xff)
                    596:                                        errx(1, "%s: Bad value notation (%s)",
                    597:                                            argv[i], argv[i + 2]);
                    598:                                str[strl++] = (unsigned char) lval;
                    599:                                tmpstr = endstr + 1;
                    600:                        } while (endstr[0] != '\0');
                    601:                        goto pastestring;
                    602:                case 'u':
                    603:                case 'i':
                    604:                        lval = strtonum(argv[i + 2], LLONG_MIN, LLONG_MAX,
                    605:                            &errstr);
                    606:                        if (errstr != NULL)
                    607:                                errx(1, "%s: Bad value notation (%s)", argv[i],
                    608:                                    argv[i + 2]);
                    609:                        if ((varbind = ber_printf_elements(varbind, "{Oi}",
                    610:                            &oid, lval)) == NULL)
                    611:                                err(1, "ber_printf_elements");
                    612:                        break;
                    613:                case 'n':
                    614:                        if ((varbind = ber_printf_elements(varbind, "{O0}",
                    615:                            &oid)) == NULL)
                    616:                                err(1, "ber_printf_elements");
                    617:                        break;
                    618:                case 'o':
                    619:                        if (smi_string2oid(argv[i + 2], &oidval) == -1)
                    620:                                errx(1, "%s: Unknown Object Identifier (Sub-id "
                    621:                                    "not found: (top) -> %s)", argv[i],
                    622:                                    argv[i + 2]);
                    623:                        if ((varbind = ber_printf_elements(varbind, "{OO}",
                    624:                            &oid, &oidval)) == NULL)
                    625:                                err(1, "ber_printf_elements");
                    626:                        break;
                    627:                case 's':
                    628:                        if ((str = strdup(argv[i + 2])) == NULL)
                    629:                                err(1, NULL);
                    630:                        strl = strlen(argv[i + 2]);
                    631: pastestring:
                    632:                        if ((varbind = ber_printf_elements(varbind, "{Ox}",
                    633:                            &oid, str, strl)) == NULL)
                    634:                                err(1, "ber_printf_elements");
                    635:                        free(str);
                    636:                        break;
                    637:                case 't':
                    638:                        lval = strtonum(argv[i + 2], LLONG_MIN, LLONG_MAX,
                    639:                            &errstr);
                    640:                        if (errstr != NULL)
                    641:                                errx(1, "%s: Bad value notation (%s)", argv[i],
                    642:                                    argv[i + 2]);
                    643:                        if ((varbind = ber_printf_elements(varbind, "{Oit}",
                    644:                            &oid, lval, BER_CLASS_APPLICATION,
                    645:                            SNMP_T_TIMETICKS)) == NULL)
                    646:                                err(1, "ber_printf_elements");
                    647:                        break;
                    648:                case 'x':
                    649:                        /* String always shrinks */
                    650:                        if ((str = malloc(strlen(argv[i + 2]))) == NULL)
1.5       martijn   651:                                err(1, "malloc");
1.1       martijn   652:                        tmpstr = argv[i + 2];
                    653:                        strl = 0;
                    654:                        do {
                    655:                                lval = strtoll(tmpstr, &endstr, 16);
                    656:                                if (endstr[0] != ' ' && endstr[0] != '\t' &&
                    657:                                    endstr[0] != '\0')
                    658:                                        errx(1, "%s: Bad value notation (%s)",
                    659:                                            argv[i], argv[i + 2]);
                    660:                                if (tmpstr == endstr) {
                    661:                                        tmpstr++;
                    662:                                        continue;
                    663:                                }
                    664:                                if (lval < 0 || lval > 0xff)
                    665:                                        errx(1, "%s: Bad value notation (%s)",
                    666:                                            argv[i], argv[i + 2]);
                    667:                                str[strl++] = (unsigned char) lval;
                    668:                                tmpstr = endstr + 1;
                    669:                        } while (endstr[0] != '\0');
                    670:                        goto pastestring;
                    671:                default:
                    672:                        usage();
                    673:                }
                    674:                if (pdu == NULL)
                    675:                        pdu = varbind;
                    676:        }
                    677:
                    678:        snmp_trap(agent, &ts, &trapoid, pdu);
                    679:
                    680:        return 0;
                    681: }
                    682:
                    683: int
                    684: snmpc_mibtree(int argc, char *argv[])
                    685: {
                    686:        struct oid *oid;
                    687:        char buf[BUFSIZ];
                    688:
                    689:        for (oid = NULL; (oid = smi_foreach(oid, 0)) != NULL;) {
                    690:                smi_oid2string(&oid->o_id, buf, sizeof(buf), oid_lookup);
                    691:                printf("%s\n", buf);
                    692:        }
                    693:        return 0;
                    694: }
                    695:
                    696: int
                    697: snmpc_print(struct ber_element *elm)
                    698: {
                    699:        struct ber_oid oid;
                    700:        char oids[SNMP_MAX_OID_STRLEN];
                    701:        char *value;
                    702:
                    703:        elm = elm->be_sub;
                    704:        if (ber_get_oid(elm, &oid) != 0) {
                    705:                errno = EINVAL;
                    706:                return 0;
                    707:        }
                    708:
                    709:        elm = elm->be_next;
                    710:        value = smi_print_element(elm, smi_print_hint, output_string, oid_lookup);
                    711:        if (value == NULL)
                    712:                return 0;
                    713:
                    714:        if (print_varbind_only)
                    715:                printf("%s\n", value);
                    716:        else if (print_equals) {
                    717:                smi_oid2string(&oid, oids, sizeof(oids), oid_lookup);
                    718:                printf("%s = %s\n", oids, value);
                    719:        } else {
                    720:                smi_oid2string(&oid, oids, sizeof(oids), oid_lookup);
                    721:                printf("%s %s\n", oids, value);
                    722:        }
                    723:        free(value);
1.2       deraadt   724:
1.1       martijn   725:        return 1;
                    726: }
                    727:
                    728: __dead void
                    729: snmpc_printerror(enum snmp_error error, char *oid)
                    730: {
1.2       deraadt   731:        switch (error) {
1.1       martijn   732:        case SNMP_ERROR_NONE:
                    733:                errx(1, "No error, how did I get here?");
                    734:        case SNMP_ERROR_TOOBIG:
                    735:                errx(1, "Can't parse oid %s: Response too big", oid);
                    736:        case SNMP_ERROR_NOSUCHNAME:
                    737:                errx(1, "Can't parse oid %s: No such object", oid);
                    738:        case SNMP_ERROR_BADVALUE:
                    739:                errx(1, "Can't parse oid %s: Bad value", oid);
                    740:        case SNMP_ERROR_READONLY:
                    741:                errx(1, "Can't parse oid %s: Read only", oid);
                    742:        case SNMP_ERROR_GENERR:
                    743:                errx(1, "Can't parse oid %s: Generic error", oid);
                    744:        case SNMP_ERROR_NOACCESS:
                    745:                errx(1, "Can't parse oid %s: Access denied", oid);
                    746:        case SNMP_ERROR_WRONGTYPE:
                    747:                errx(1, "Can't parse oid %s: Wrong type", oid);
                    748:        case SNMP_ERROR_WRONGLENGTH:
                    749:                errx(1, "Can't parse oid %s: Wrong length", oid);
                    750:        case SNMP_ERROR_WRONGENC:
                    751:                errx(1, "Can't parse oid %s: Wrong encoding", oid);
                    752:        case SNMP_ERROR_WRONGVALUE:
                    753:                errx(1, "Can't parse oid %s: Wrong value", oid);
                    754:        case SNMP_ERROR_NOCREATION:
                    755:                errx(1, "Can't parse oid %s: Can't be created", oid);
                    756:        case SNMP_ERROR_INCONVALUE:
                    757:                errx(1, "Can't parse oid %s: Inconsistent value", oid);
                    758:        case SNMP_ERROR_RESUNAVAIL:
                    759:                errx(1, "Can't parse oid %s: Resource unavailable", oid);
                    760:        case SNMP_ERROR_COMMITFAILED:
                    761:                errx(1, "Can't parse oid %s: Commit failed", oid);
                    762:        case SNMP_ERROR_UNDOFAILED:
                    763:                errx(1, "Can't parse oid %s: Undo faild", oid);
                    764:        case SNMP_ERROR_AUTHERROR:
                    765:                errx(1, "Can't parse oid %s: Authorization error", oid);
                    766:        case SNMP_ERROR_NOTWRITABLE:
                    767:                errx(1, "Can't parse oid %s: Not writable", oid);
                    768:        case SNMP_ERROR_INCONNAME:
                    769:                errx(1, "Can't parse oid %s: Inconsistent name", oid);
                    770:        }
                    771:        errx(1, "Can't parse oid %s: Unknown error (%d)", oid, error);
                    772: }
                    773:
                    774: int
                    775: snmpc_parseagent(char *agent, char *defaultport)
                    776: {
                    777:        struct addrinfo hints, *ai, *ai0 = NULL;
                    778:        struct sockaddr_un saddr;
                    779:        char *agentdup, *specifier, *hostname, *port = NULL;
                    780:        int error;
                    781:        int s;
                    782:
                    783:        if ((agentdup = specifier = strdup(agent)) == NULL)
                    784:                err(1, NULL);
                    785:
                    786:        bzero(&hints, sizeof(hints));
                    787:        if ((hostname = strchr(specifier, ':')) != NULL) {
                    788:                *hostname++ = '\0';
                    789:                if (strcasecmp(specifier, "udp") == 0) {
                    790:                        hints.ai_family = AF_INET;
                    791:                        hints.ai_socktype = SOCK_DGRAM;
                    792:                } else if (strcasecmp(specifier, "tcp") == 0) {
                    793:                        hints.ai_family = AF_INET;
                    794:                        hints.ai_socktype = SOCK_STREAM;
                    795:                } else if (strcasecmp(specifier, "udp6") == 0 ||
                    796:                    strcasecmp(specifier, "udpv6") == 0 ||
                    797:                    strcasecmp(specifier, "udpipv6") == 0) {
                    798:                        hints.ai_family = AF_INET6;
                    799:                        hints.ai_socktype = SOCK_DGRAM;
                    800:                } else if (strcasecmp(specifier, "tcp6") == 0 ||
                    801:                    strcasecmp(specifier, "tcpv6") == 0 ||
                    802:                    strcasecmp(specifier, "tcpipv6") == 0) {
                    803:                        hints.ai_family = AF_INET6;
                    804:                        hints.ai_socktype = SOCK_STREAM;
                    805:                } else if (strcasecmp(specifier, "unix") == 0) {
                    806:                        hints.ai_family = AF_UNIX;
                    807:                        hints.ai_socktype = SOCK_STREAM;
                    808:                        hints.ai_addr = (struct sockaddr *)&saddr;
                    809:                        hints.ai_addrlen = sizeof(saddr);
                    810:                        saddr.sun_len = sizeof(saddr);
                    811:                        saddr.sun_family = AF_UNIX;
                    812:                        if (strlcpy(saddr.sun_path, hostname,
                    813:                            sizeof(saddr.sun_path)) > sizeof(saddr.sun_path))
                    814:                                errx(1, "Hostname path too long");
                    815:                        ai = &hints;
                    816:                } else {
                    817:                        port = hostname;
                    818:                        hostname = specifier;
                    819:                        specifier = NULL;
                    820:                        hints.ai_family = AF_INET;
                    821:                        hints.ai_socktype = SOCK_DGRAM;
                    822:                }
                    823:                if (port == NULL) {
                    824:                        if (hints.ai_family == AF_INET) {
                    825:                                if ((port = strchr(hostname, ':')) != NULL)
                    826:                                        *port++ = '\0';
                    827:                        } else if (hints.ai_family == AF_INET6) {
                    828:                                if (hostname[0] == '[') {
                    829:                                        hostname++;
                    830:                                        if ((port = strchr(hostname, ']')) == NULL)
                    831:                                                errx(1, "invalid agent");
                    832:                                        *port++ = '\0';
                    833:                                        if (port[0] == ':')
                    834:                                                *port++ = '\0';
                    835:                                        else
                    836:                                                port = NULL;
                    837:                                } else {
                    838:                                        if ((port = strrchr(hostname, ':')) == NULL)
                    839:                                                errx(1, "invalid agent");
                    840:                                        *port++ = '\0';
                    841:                                }
                    842:                        }
                    843:                }
                    844:        } else {
                    845:                hostname = specifier;
                    846:                hints.ai_family = AF_INET;
                    847:                hints.ai_socktype = SOCK_DGRAM;
                    848:        }
                    849:
                    850:        if (hints.ai_family != AF_UNIX) {
                    851:                if (port == NULL)
                    852:                        port = defaultport;
                    853:                error = getaddrinfo(hostname, port, &hints, &ai0);
                    854:                if (error)
                    855:                        errx(1, "%s", gai_strerror(error));
                    856:                s = -1;
                    857:                for (ai = ai0; ai != NULL; ai = ai->ai_next) {
                    858:                        if ((s = socket(ai->ai_family, ai->ai_socktype,
                    859:                            ai->ai_protocol)) == -1)
                    860:                                continue;
                    861:                        break;
                    862:                }
                    863:        } else
                    864:                s = socket(hints.ai_family, hints.ai_socktype,
                    865:                    hints.ai_protocol);
                    866:        if (s == -1)
                    867:                err(1, "socket");
                    868:
                    869:        if (connect(s, (struct sockaddr *)ai->ai_addr, ai->ai_addrlen) == -1)
                    870:                err(1, "Can't connect to %s", agent);
                    871:
                    872:        if (ai0 != NULL)
                    873:                freeaddrinfo(ai0);
                    874:        free(agentdup);
                    875:        return s;
                    876: }
                    877:
                    878: __dead void
                    879: usage(void)
                    880: {
                    881:        size_t i;
                    882:
                    883:        if (snmp_app != NULL) {
1.4       martijn   884:                fprintf(stderr, "usage: snmp %s%s%s%s\n",
                    885:                    snmp_app->name,
1.1       martijn   886:                    snmp_app->usecommonopt ?
1.4       martijn   887:                    " [-c community] [-r retries] [-t timeout] [-v version]\n"
                    888:                    "            [-O afnqvxSQ]" : "",
1.1       martijn   889:                    snmp_app->usage == NULL ? "" : " ",
                    890:                    snmp_app->usage == NULL ? "" : snmp_app->usage);
                    891:                exit(1);
                    892:        }
                    893:        for (i = 0; i < (sizeof(snmp_apps)/sizeof(*snmp_apps)); i++) {
1.4       martijn   894:                if (i == 0)
                    895:                        fprintf(stderr, "usage: ");
                    896:                else
                    897:                        fprintf(stderr, "       ");
                    898:                fprintf(stderr, "snmp %s%s %s\n",
                    899:                    snmp_apps[i].name,
1.1       martijn   900:                    snmp_apps[i].usecommonopt ?
1.4       martijn   901:                    " [-c community] [-r retries] [-t timeout] [-v version]\n"
                    902:                    "            [-O afnqvxSQ]" : "",
                    903:                    snmp_apps[i].usage ? snmp_apps[i].usage : "");
1.1       martijn   904:        }
                    905:        exit(1);
                    906: }