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

1.2     ! deraadt     1: /*     $OpenBSD: snmpc.c,v 1.1 2019/08/09 06:17:59 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 },
        !            64:        { "walk", 1, "C:", "[-C cIipt] [-C E OID] agent [oid]", snmpc_walk },
        !            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));
                    320:        for (i = 0; i < argc; i++) {
                    321:                if (smi_string2oid(argv[i], &oid[i]) == -1)
                    322:                        errx(1, "%s: Unknown object identifier", argv[0]);
                    323:        }
                    324:        if (strcmp(snmp_app->name, "getnext") == 0) {
                    325:                if ((pdu = snmp_getnext(agent, oid, argc)) == NULL)
                    326:                        err(1, "getnext");
                    327:        } else if (strcmp(snmp_app->name, "bulkget") == 0) {
                    328:                if (version < SNMP_V2C)
                    329:                        errx(1, "Cannot send V2 PDU on V1 session");
                    330:                if (non_repeaters > argc)
                    331:                        errx(1, "need more objects than -Cn<num>");
                    332:                if ((pdu = snmp_getbulk(agent, oid, argc, non_repeaters,
                    333:                    max_repetitions)) == NULL)
                    334:                        err(1, "bulkget");
                    335:        } else {
                    336:                if ((pdu = snmp_get(agent, oid, argc)) == NULL)
                    337:                        err(1, "get");
                    338:        }
                    339:
                    340:        (void) ber_scanf_elements(pdu, "{Sdd{e", &errorstatus, &errorindex,
                    341:            &varbind);
                    342:        if (errorstatus != 0)
                    343:                snmpc_printerror((enum snmp_error) errorstatus,
                    344:                    argv[errorindex]);
                    345:
                    346:        for (; varbind != NULL; varbind = varbind->be_next) {
                    347:                if (!snmpc_print(varbind))
                    348:                        err(1, "Can't print response");
                    349:        }
                    350:        ber_free_elements(pdu);
                    351:        snmp_free_agent(agent);
                    352:        return 0;
                    353: }
                    354:
                    355: int
                    356: snmpc_walk(int argc, char *argv[])
                    357: {
                    358:        struct ber_oid oid, loid, noid;
                    359:        struct ber_element *pdu, *varbind, *value;
                    360:        struct timespec start, finish;
                    361:        struct snmp_agent *agent;
                    362:        const char *oids;
                    363:        char oidstr[SNMP_MAX_OID_STRLEN];
                    364:        int n = 0, prev_cmp;
                    365:        int errorstatus, errorindex;
                    366:
                    367:        if (strcmp(snmp_app->name, "bulkwalk") == 0 && version < SNMP_V2C)
                    368:                errx(1, "Cannot send V2 PDU on V1 session");
                    369:        if (argc < 1 || argc > 2)
                    370:                usage();
                    371:        oids = argc == 1 ? mib : argv[1];
                    372:
                    373:        agent = snmp_connect_v12(snmpc_parseagent(argv[0], "161"), version, community);
                    374:        if (agent == NULL)
                    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,
                    395:                            argv[errorindex]);
                    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,
                    452:                            argv[errorindex]);
                    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:
                    496:        agent = snmp_connect_v12(snmpc_parseagent(argv[0], "162"),
                    497:            version, community);
                    498:        if (agent == NULL)
                    499:                err(1, "%s", snmp_app->name);
                    500:
                    501:        if (pledge("stdio", NULL) == -1)
                    502:                err(1, "pledge");
                    503:
                    504:        if (argv[1][0] == '\0') {
                    505:                if (clock_gettime(CLOCK_UPTIME, &ts) == -1)
                    506:                        err(1, "clock_gettime");
                    507:        } else {
                    508:                lval = strtonum(argv[1], 0, LLONG_MAX, &errstr);
                    509:                if (errstr != NULL)
                    510:                        errx(1, "Bad value notation (%s)", argv[1]);
                    511:                ts.tv_sec = lval / 100;
                    512:                ts.tv_nsec = (lval % 100) * 10000000;
                    513:        }
                    514:        if (smi_string2oid(argv[2], &trapoid) == -1)
                    515:                errx(1, "Invalid oid: %s\n", argv[2]);
                    516:
                    517:        argc -= 3;
                    518:        argv += 3;
                    519:        for (i = 0; i < argc; i += 3) {
                    520:                if (smi_string2oid(argv[i], &oid) == -1)
                    521:                        errx(1, "Invalid oid: %s\n", argv[i]);
                    522:                switch (argv[i + 1][0]) {
                    523:                case 'a':
                    524:                        ret = inet_pton(AF_INET, argv[i + 2], &addr4);
                    525:                        if (ret == -1)
                    526:                                err(1, "inet_pton");
                    527:                        if (ret == 0)
                    528:                                errx(1, "%s: Bad value notation (%s)", argv[i],
                    529:                                    argv[i + 2]);
                    530:                        if ((varbind = ber_printf_elements(varbind, "{Oxt}",
                    531:                            &oid, addr, sizeof(addr4), BER_CLASS_APPLICATION,
                    532:                            SNMP_T_IPADDR)) == NULL)
                    533:                                err(1, "ber_printf_elements");
                    534:                        break;
                    535:                case 'b':
                    536:                        tmpstr = argv[i + 2];
                    537:                        strl = 0;
                    538:                        do {
                    539:                                lval = strtoll(tmpstr, &endstr, 10);
                    540:                                if (endstr[0] != ' ' && endstr[0] != '\t' &&
                    541:                                    endstr[0] != ',' && endstr[0] != '\0')
                    542:                                        errx(1, "%s: Bad value notation (%s)",
                    543:                                            argv[i], argv[i + 2]);
                    544:                                if (tmpstr == endstr) {
                    545:                                        tmpstr++;
                    546:                                        continue;
                    547:                                }
                    548:                                if (lval < 0)
                    549:                                        errx(1, "%s: Bad value notation (%s)",
                    550:                                            argv[i], argv[i + 2]);
                    551:                                byte = lval / 8;
                    552:                                if (byte >= strl) {
                    553:                                        if ((str = recallocarray(str, strl,
                    554:                                            byte + 1, 1)) == NULL)
                    555:                                                err(1, NULL);
                    556:                                        strl = byte + 1;
                    557:                                }
                    558:                                str[byte] |= 0x80 >> (lval % 8);
                    559:                                tmpstr = endstr + 1;
                    560:                        } while (endstr[0] != '\0');
                    561:                        /*
                    562:                         * RFC3416 Section 2.5
                    563:                         * A BITS value is encoded as an OCTET STRING
                    564:                         */
                    565:                        goto pastestring;
                    566:                case 'c':
                    567:                        lval = strtonum(argv[i + 2], INT32_MIN, INT32_MAX,
                    568:                            &errstr);
                    569:                        if (errstr != NULL)
                    570:                                errx(1, "%s: Bad value notation (%s)", argv[i],
                    571:                                    argv[i + 2]);
                    572:                        if ((varbind = ber_printf_elements(varbind, "{Oit}",
                    573:                            &oid, lval, BER_CLASS_APPLICATION,
                    574:                            SNMP_T_COUNTER32)) == NULL)
                    575:                                err(1, "ber_printf_elements");
                    576:                        break;
                    577:                case 'd':
                    578:                        /* String always shrinks */
                    579:                        if ((str = malloc(strlen(argv[i + 2]))) == NULL)
                    580:                                err(1, NULL);
                    581:                        tmpstr = argv[i + 2];
                    582:                        strl = 0;
                    583:                        do {
                    584:                                lval = strtoll(tmpstr, &endstr, 10);
                    585:                                if (endstr[0] != ' ' && endstr[0] != '\t' &&
                    586:                                    endstr[0] != '\0')
                    587:                                        errx(1, "%s: Bad value notation (%s)",
                    588:                                            argv[i], argv[i + 2]);
                    589:                                if (tmpstr == endstr) {
                    590:                                        tmpstr++;
                    591:                                        continue;
                    592:                                }
                    593:                                if (lval < 0 || lval > 0xff)
                    594:                                        errx(1, "%s: Bad value notation (%s)",
                    595:                                            argv[i], argv[i + 2]);
                    596:                                str[strl++] = (unsigned char) lval;
                    597:                                tmpstr = endstr + 1;
                    598:                        } while (endstr[0] != '\0');
                    599:                        goto pastestring;
                    600:                case 'u':
                    601:                case 'i':
                    602:                        lval = strtonum(argv[i + 2], LLONG_MIN, LLONG_MAX,
                    603:                            &errstr);
                    604:                        if (errstr != NULL)
                    605:                                errx(1, "%s: Bad value notation (%s)", argv[i],
                    606:                                    argv[i + 2]);
                    607:                        if ((varbind = ber_printf_elements(varbind, "{Oi}",
                    608:                            &oid, lval)) == NULL)
                    609:                                err(1, "ber_printf_elements");
                    610:                        break;
                    611:                case 'n':
                    612:                        if ((varbind = ber_printf_elements(varbind, "{O0}",
                    613:                            &oid)) == NULL)
                    614:                                err(1, "ber_printf_elements");
                    615:                        break;
                    616:                case 'o':
                    617:                        if (smi_string2oid(argv[i + 2], &oidval) == -1)
                    618:                                errx(1, "%s: Unknown Object Identifier (Sub-id "
                    619:                                    "not found: (top) -> %s)", argv[i],
                    620:                                    argv[i + 2]);
                    621:                        if ((varbind = ber_printf_elements(varbind, "{OO}",
                    622:                            &oid, &oidval)) == NULL)
                    623:                                err(1, "ber_printf_elements");
                    624:                        break;
                    625:                case 's':
                    626:                        if ((str = strdup(argv[i + 2])) == NULL)
                    627:                                err(1, NULL);
                    628:                        strl = strlen(argv[i + 2]);
                    629: pastestring:
                    630:                        if ((varbind = ber_printf_elements(varbind, "{Ox}",
                    631:                            &oid, str, strl)) == NULL)
                    632:                                err(1, "ber_printf_elements");
                    633:                        free(str);
                    634:                        break;
                    635:                case 't':
                    636:                        lval = strtonum(argv[i + 2], LLONG_MIN, LLONG_MAX,
                    637:                            &errstr);
                    638:                        if (errstr != NULL)
                    639:                                errx(1, "%s: Bad value notation (%s)", argv[i],
                    640:                                    argv[i + 2]);
                    641:                        if ((varbind = ber_printf_elements(varbind, "{Oit}",
                    642:                            &oid, lval, BER_CLASS_APPLICATION,
                    643:                            SNMP_T_TIMETICKS)) == NULL)
                    644:                                err(1, "ber_printf_elements");
                    645:                        break;
                    646:                case 'x':
                    647:                        /* String always shrinks */
                    648:                        if ((str = malloc(strlen(argv[i + 2]))) == NULL)
                    649:                                err(1, NULL);
                    650:                        tmpstr = argv[i + 2];
                    651:                        strl = 0;
                    652:                        do {
                    653:                                lval = strtoll(tmpstr, &endstr, 16);
                    654:                                if (endstr[0] != ' ' && endstr[0] != '\t' &&
                    655:                                    endstr[0] != '\0')
                    656:                                        errx(1, "%s: Bad value notation (%s)",
                    657:                                            argv[i], argv[i + 2]);
                    658:                                if (tmpstr == endstr) {
                    659:                                        tmpstr++;
                    660:                                        continue;
                    661:                                }
                    662:                                if (lval < 0 || lval > 0xff)
                    663:                                        errx(1, "%s: Bad value notation (%s)",
                    664:                                            argv[i], argv[i + 2]);
                    665:                                str[strl++] = (unsigned char) lval;
                    666:                                tmpstr = endstr + 1;
                    667:                        } while (endstr[0] != '\0');
                    668:                        goto pastestring;
                    669:                default:
                    670:                        usage();
                    671:                }
                    672:                if (pdu == NULL)
                    673:                        pdu = varbind;
                    674:        }
                    675:
                    676:        snmp_trap(agent, &ts, &trapoid, pdu);
                    677:
                    678:        return 0;
                    679: }
                    680:
                    681: int
                    682: snmpc_mibtree(int argc, char *argv[])
                    683: {
                    684:        struct oid *oid;
                    685:        char buf[BUFSIZ];
                    686:
                    687:        for (oid = NULL; (oid = smi_foreach(oid, 0)) != NULL;) {
                    688:                smi_oid2string(&oid->o_id, buf, sizeof(buf), oid_lookup);
                    689:                printf("%s\n", buf);
                    690:        }
                    691:        return 0;
                    692: }
                    693:
                    694: int
                    695: snmpc_print(struct ber_element *elm)
                    696: {
                    697:        struct ber_oid oid;
                    698:        char oids[SNMP_MAX_OID_STRLEN];
                    699:        char *value;
                    700:
                    701:        elm = elm->be_sub;
                    702:        if (ber_get_oid(elm, &oid) != 0) {
                    703:                errno = EINVAL;
                    704:                return 0;
                    705:        }
                    706:
                    707:        elm = elm->be_next;
                    708:        value = smi_print_element(elm, smi_print_hint, output_string, oid_lookup);
                    709:        if (value == NULL)
                    710:                return 0;
                    711:
                    712:        if (print_varbind_only)
                    713:                printf("%s\n", value);
                    714:        else if (print_equals) {
                    715:                smi_oid2string(&oid, oids, sizeof(oids), oid_lookup);
                    716:                printf("%s = %s\n", oids, value);
                    717:        } else {
                    718:                smi_oid2string(&oid, oids, sizeof(oids), oid_lookup);
                    719:                printf("%s %s\n", oids, value);
                    720:        }
                    721:        free(value);
1.2     ! deraadt   722:
1.1       martijn   723:        return 1;
                    724: }
                    725:
                    726: __dead void
                    727: snmpc_printerror(enum snmp_error error, char *oid)
                    728: {
1.2     ! deraadt   729:        switch (error) {
1.1       martijn   730:        case SNMP_ERROR_NONE:
                    731:                errx(1, "No error, how did I get here?");
                    732:        case SNMP_ERROR_TOOBIG:
                    733:                errx(1, "Can't parse oid %s: Response too big", oid);
                    734:        case SNMP_ERROR_NOSUCHNAME:
                    735:                errx(1, "Can't parse oid %s: No such object", oid);
                    736:        case SNMP_ERROR_BADVALUE:
                    737:                errx(1, "Can't parse oid %s: Bad value", oid);
                    738:        case SNMP_ERROR_READONLY:
                    739:                errx(1, "Can't parse oid %s: Read only", oid);
                    740:        case SNMP_ERROR_GENERR:
                    741:                errx(1, "Can't parse oid %s: Generic error", oid);
                    742:        case SNMP_ERROR_NOACCESS:
                    743:                errx(1, "Can't parse oid %s: Access denied", oid);
                    744:        case SNMP_ERROR_WRONGTYPE:
                    745:                errx(1, "Can't parse oid %s: Wrong type", oid);
                    746:        case SNMP_ERROR_WRONGLENGTH:
                    747:                errx(1, "Can't parse oid %s: Wrong length", oid);
                    748:        case SNMP_ERROR_WRONGENC:
                    749:                errx(1, "Can't parse oid %s: Wrong encoding", oid);
                    750:        case SNMP_ERROR_WRONGVALUE:
                    751:                errx(1, "Can't parse oid %s: Wrong value", oid);
                    752:        case SNMP_ERROR_NOCREATION:
                    753:                errx(1, "Can't parse oid %s: Can't be created", oid);
                    754:        case SNMP_ERROR_INCONVALUE:
                    755:                errx(1, "Can't parse oid %s: Inconsistent value", oid);
                    756:        case SNMP_ERROR_RESUNAVAIL:
                    757:                errx(1, "Can't parse oid %s: Resource unavailable", oid);
                    758:        case SNMP_ERROR_COMMITFAILED:
                    759:                errx(1, "Can't parse oid %s: Commit failed", oid);
                    760:        case SNMP_ERROR_UNDOFAILED:
                    761:                errx(1, "Can't parse oid %s: Undo faild", oid);
                    762:        case SNMP_ERROR_AUTHERROR:
                    763:                errx(1, "Can't parse oid %s: Authorization error", oid);
                    764:        case SNMP_ERROR_NOTWRITABLE:
                    765:                errx(1, "Can't parse oid %s: Not writable", oid);
                    766:        case SNMP_ERROR_INCONNAME:
                    767:                errx(1, "Can't parse oid %s: Inconsistent name", oid);
                    768:        }
                    769:        errx(1, "Can't parse oid %s: Unknown error (%d)", oid, error);
                    770: }
                    771:
                    772: int
                    773: snmpc_parseagent(char *agent, char *defaultport)
                    774: {
                    775:        struct addrinfo hints, *ai, *ai0 = NULL;
                    776:        struct sockaddr_un saddr;
                    777:        char *agentdup, *specifier, *hostname, *port = NULL;
                    778:        int error;
                    779:        int s;
                    780:
                    781:        if ((agentdup = specifier = strdup(agent)) == NULL)
                    782:                err(1, NULL);
                    783:
                    784:        bzero(&hints, sizeof(hints));
                    785:        if ((hostname = strchr(specifier, ':')) != NULL) {
                    786:                *hostname++ = '\0';
                    787:                if (strcasecmp(specifier, "udp") == 0) {
                    788:                        hints.ai_family = AF_INET;
                    789:                        hints.ai_socktype = SOCK_DGRAM;
                    790:                } else if (strcasecmp(specifier, "tcp") == 0) {
                    791:                        hints.ai_family = AF_INET;
                    792:                        hints.ai_socktype = SOCK_STREAM;
                    793:                } else if (strcasecmp(specifier, "udp6") == 0 ||
                    794:                    strcasecmp(specifier, "udpv6") == 0 ||
                    795:                    strcasecmp(specifier, "udpipv6") == 0) {
                    796:                        hints.ai_family = AF_INET6;
                    797:                        hints.ai_socktype = SOCK_DGRAM;
                    798:                } else if (strcasecmp(specifier, "tcp6") == 0 ||
                    799:                    strcasecmp(specifier, "tcpv6") == 0 ||
                    800:                    strcasecmp(specifier, "tcpipv6") == 0) {
                    801:                        hints.ai_family = AF_INET6;
                    802:                        hints.ai_socktype = SOCK_STREAM;
                    803:                } else if (strcasecmp(specifier, "unix") == 0) {
                    804:                        hints.ai_family = AF_UNIX;
                    805:                        hints.ai_socktype = SOCK_STREAM;
                    806:                        hints.ai_addr = (struct sockaddr *)&saddr;
                    807:                        hints.ai_addrlen = sizeof(saddr);
                    808:                        saddr.sun_len = sizeof(saddr);
                    809:                        saddr.sun_family = AF_UNIX;
                    810:                        if (strlcpy(saddr.sun_path, hostname,
                    811:                            sizeof(saddr.sun_path)) > sizeof(saddr.sun_path))
                    812:                                errx(1, "Hostname path too long");
                    813:                        ai = &hints;
                    814:                } else {
                    815:                        port = hostname;
                    816:                        hostname = specifier;
                    817:                        specifier = NULL;
                    818:                        hints.ai_family = AF_INET;
                    819:                        hints.ai_socktype = SOCK_DGRAM;
                    820:                }
                    821:                if (port == NULL) {
                    822:                        if (hints.ai_family == AF_INET) {
                    823:                                if ((port = strchr(hostname, ':')) != NULL)
                    824:                                        *port++ = '\0';
                    825:                        } else if (hints.ai_family == AF_INET6) {
                    826:                                if (hostname[0] == '[') {
                    827:                                        hostname++;
                    828:                                        if ((port = strchr(hostname, ']')) == NULL)
                    829:                                                errx(1, "invalid agent");
                    830:                                        *port++ = '\0';
                    831:                                        if (port[0] == ':')
                    832:                                                *port++ = '\0';
                    833:                                        else
                    834:                                                port = NULL;
                    835:                                } else {
                    836:                                        if ((port = strrchr(hostname, ':')) == NULL)
                    837:                                                errx(1, "invalid agent");
                    838:                                        *port++ = '\0';
                    839:                                }
                    840:                        }
                    841:                }
                    842:        } else {
                    843:                hostname = specifier;
                    844:                hints.ai_family = AF_INET;
                    845:                hints.ai_socktype = SOCK_DGRAM;
                    846:        }
                    847:
                    848:        if (hints.ai_family != AF_UNIX) {
                    849:                if (port == NULL)
                    850:                        port = defaultport;
                    851:                error = getaddrinfo(hostname, port, &hints, &ai0);
                    852:                if (error)
                    853:                        errx(1, "%s", gai_strerror(error));
                    854:                s = -1;
                    855:                for (ai = ai0; ai != NULL; ai = ai->ai_next) {
                    856:                        if ((s = socket(ai->ai_family, ai->ai_socktype,
                    857:                            ai->ai_protocol)) == -1)
                    858:                                continue;
                    859:                        break;
                    860:                }
                    861:        } else
                    862:                s = socket(hints.ai_family, hints.ai_socktype,
                    863:                    hints.ai_protocol);
                    864:        if (s == -1)
                    865:                err(1, "socket");
                    866:
                    867:        if (connect(s, (struct sockaddr *)ai->ai_addr, ai->ai_addrlen) == -1)
                    868:                err(1, "Can't connect to %s", agent);
                    869:
                    870:        if (ai0 != NULL)
                    871:                freeaddrinfo(ai0);
                    872:        free(agentdup);
                    873:        return s;
                    874: }
                    875:
                    876: __dead void
                    877: usage(void)
                    878: {
                    879:        size_t i;
                    880:
                    881:        extern char *__progname;
                    882:
                    883:        if (snmp_app != NULL) {
                    884:                fprintf(stderr, "usage: %s %s%s%s%s\n",
                    885:                    __progname, snmp_app->name,
                    886:                    snmp_app->usecommonopt ?
                    887:                    " [-c community] [-r retries] [-t timeout] "
                    888:                    "[-v protocol version] [-O afnqvxSQ]" : "",
                    889:                    snmp_app->usage == NULL ? "" : " ",
                    890:                    snmp_app->usage == NULL ? "" : snmp_app->usage);
                    891:                exit(1);
                    892:        }
                    893:        fprintf(stderr, "usage: \n");
                    894:        for (i = 0; i < (sizeof(snmp_apps)/sizeof(*snmp_apps)); i++) {
                    895:                fprintf(stderr, "%*s %s%s%s%s\n",
                    896:                    (int) (sizeof("usage:") + strlen(__progname)),
                    897:                    __progname, snmp_apps[i].name,
                    898:                    snmp_apps[i].usecommonopt ?
                    899:                    " [-c community] [-r retries] [-t timeout] "
                    900:                    "[-v protocol version] [-O afnqvxSQ]" : "",
                    901:                    snmp_apps[i].usage == NULL ? "" : " ",
                    902:                    snmp_apps[i].usage == NULL ? "" : snmp_apps[i].usage);
                    903:        }
                    904:        exit(1);
                    905: }