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

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