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

1.32    ! jsg         1: /*     $OpenBSD: snmpc.c,v 1.31 2020/12/02 15:45:51 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>
1.10      martijn    26: #include <openssl/evp.h>
1.1       martijn    27:
                     28: #include <ber.h>
1.9       martijn    29: #include <ctype.h>
1.1       martijn    30: #include <err.h>
                     31: #include <errno.h>
1.28      martijn    32: #include <locale.h>
1.1       martijn    33: #include <netdb.h>
                     34: #include <poll.h>
                     35: #include <stdio.h>
                     36: #include <stdlib.h>
                     37: #include <stdint.h>
                     38: #include <string.h>
                     39: #include <time.h>
                     40: #include <unistd.h>
1.19      martijn    41: #include <util.h>
1.29      martijn    42: #include <wchar.h>
1.1       martijn    43:
                     44: #include "smi.h"
                     45: #include "snmp.h"
1.9       martijn    46: #include "usm.h"
1.1       martijn    47:
1.11      martijn    48: #define GETOPT_COMMON          "A:a:c:E:e:K:k:l:n:O:r:t:u:v:X:x:Z:"
1.1       martijn    49:
                     50: int snmpc_get(int, char *[]);
                     51: int snmpc_walk(int, char *[]);
1.13      martijn    52: int snmpc_set(int, char *[]);
1.1       martijn    53: int snmpc_trap(int, char *[]);
1.19      martijn    54: int snmpc_df(int, char *[]);
1.1       martijn    55: int snmpc_mibtree(int, char *[]);
1.8       martijn    56: struct snmp_agent *snmpc_connect(char *, char *);
1.1       martijn    57: int snmpc_parseagent(char *, char *);
                     58: int snmpc_print(struct ber_element *);
1.15      martijn    59: __dead void snmpc_printerror(enum snmp_error, struct ber_element *, int,
                     60:     const char *);
1.9       martijn    61: char *snmpc_hex2bin(char *, size_t *);
1.29      martijn    62: ssize_t snmpc_mbswidth(char *);
1.13      martijn    63: struct ber_element *snmpc_varbindparse(int, char *[]);
1.1       martijn    64: void usage(void);
                     65:
                     66: struct snmp_app {
                     67:        const char *name;
                     68:        const int usecommonopt;
                     69:        const char *optstring;
                     70:        const char *usage;
1.2       deraadt    71:        int (*exec)(int, char *[]);
1.1       martijn    72: };
                     73:
                     74: struct snmp_app snmp_apps[] = {
1.2       deraadt    75:        { "get", 1, NULL, "agent oid ...", snmpc_get },
                     76:        { "getnext", 1, NULL, "agent oid ...", snmpc_get },
1.20      martijn    77:        { "walk", 1, "C:", "[-C cIipt] [-C E endoid] [-C s skipoid] agent [oid]", snmpc_walk },
1.2       deraadt    78:        { "bulkget", 1, "C:", "[-C n<nonrep>r<maxrep>] agent oid ...", snmpc_get },
1.20      martijn    79:        { "bulkwalk", 1, "C:", "[-C cipn<nonrep>r<maxrep>] [-C s skipoid] agent [oid]", snmpc_walk },
1.13      martijn    80:        { "set", 1, NULL, "agent oid type value [oid type value] ...", snmpc_set },
1.2       deraadt    81:        { "trap", 1, NULL, "agent uptime oid [oid type value] ...", snmpc_trap },
1.20      martijn    82:        { "df", 1, "C:", "[-Ch] [-Cr<maxrep>] agent", snmpc_df },
1.30      martijn    83:        { "mibtree", 0, "O:", "[-O fnS] [oid ...]", snmpc_mibtree }
1.1       martijn    84: };
                     85: struct snmp_app *snmp_app = NULL;
                     86:
                     87: char *community = "public";
1.9       martijn    88: struct snmp_v3 *v3;
1.1       martijn    89: char *mib = "mib_2";
                     90: int retries = 5;
                     91: int timeout = 1;
1.9       martijn    92: enum snmp_version version = SNMP_V2C;
1.1       martijn    93: int print_equals = 1;
                     94: int print_varbind_only = 0;
                     95: int print_summary = 0;
                     96: int print_time = 0;
1.19      martijn    97: int print_human = 0;
1.1       martijn    98: int walk_check_increase = 1;
                     99: int walk_fallback_oid = 1;
                    100: int walk_include_oid = 0;
                    101: int smi_print_hint = 1;
                    102: int non_repeaters = 0;
                    103: int max_repetitions = 10;
                    104: struct ber_oid walk_end = {{0}, 0};
1.18      martijn   105: struct ber_oid *walk_skip = NULL;
                    106: size_t walk_skip_len = 0;
1.1       martijn   107: enum smi_oid_lookup oid_lookup = smi_oidl_short;
                    108: enum smi_output_string output_string = smi_os_default;
1.28      martijn   109: int utf8 = 0;
1.1       martijn   110:
                    111: int
                    112: main(int argc, char *argv[])
                    113: {
1.10      martijn   114:        const EVP_MD *md = NULL;
1.11      martijn   115:        const EVP_CIPHER *cipher = NULL;
1.9       martijn   116:        struct snmp_sec *sec;
                    117:        char *user = NULL;
1.24      martijn   118:        enum usm_key_level authkeylevel = USM_KEY_UNSET;
1.10      martijn   119:        char *authkey = NULL;
                    120:        size_t authkeylen = 0;
1.24      martijn   121:        enum usm_key_level privkeylevel = USM_KEY_UNSET;
1.11      martijn   122:        char *privkey = NULL;
                    123:        size_t privkeylen = 0;
1.9       martijn   124:        int seclevel = SNMP_MSGFLAG_REPORT;
                    125:        char *ctxname = NULL;
                    126:        char *ctxengineid = NULL, *secengineid = NULL;
                    127:        size_t ctxengineidlen, secengineidlen;
                    128:        int zflag = 0;
1.24      martijn   129:        long long boots = 0, time = 0;
1.1       martijn   130:        char optstr[BUFSIZ];
                    131:        const char *errstr;
                    132:        char *strtolp;
                    133:        int ch;
                    134:        size_t i;
                    135:
1.28      martijn   136:        /*
                    137:         * Determine if output can handle UTF-8 based on locale.
                    138:         */
                    139:        setlocale(LC_CTYPE, "");
                    140:        utf8 = MB_CUR_MAX > 1;
                    141:        /*
                    142:         * SMIv2 allows for UTF-8 text at some locations.
                    143:         * Set it explicitly so we can handle it on the input side.
                    144:         */
                    145:        if (setlocale(LC_CTYPE, "en_US.UTF-8") == NULL)
                    146:                errx(1, "setlocale(LC_CTYPE, \"en_US.UTF-8\") failed");
                    147:
1.22      martijn   148:        if (pledge("stdio inet dns unix", NULL) == -1)
1.1       martijn   149:                err(1, "pledge");
1.2       deraadt   150:
1.1       martijn   151:        if (argc <= 1)
                    152:                usage();
                    153:
1.14      bluhm     154:        optstr[0] = '\0';
1.1       martijn   155:        for (i = 0; i < sizeof(snmp_apps)/sizeof(*snmp_apps); i++) {
                    156:                if (strcmp(snmp_apps[i].name, argv[1]) == 0) {
                    157:                        snmp_app = &snmp_apps[i];
                    158:                        if (snmp_app->optstring != NULL) {
                    159:                                if (strlcpy(optstr, snmp_app->optstring,
                    160:                                    sizeof(optstr)) > sizeof(optstr))
                    161:                                        errx(1, "strlcat");
                    162:                        }
                    163:                        break;
                    164:                }
                    165:        }
                    166:        if (snmp_app == NULL)
                    167:                usage();
                    168:
                    169:        if (snmp_app->usecommonopt) {
                    170:                if (strlcat(optstr, GETOPT_COMMON, sizeof(optstr)) >
                    171:                    sizeof(optstr))
                    172:                        errx(1, "strlcpy");
                    173:        }
                    174:
                    175:        argc--;
                    176:        argv++;
                    177:
                    178:        smi_init();
                    179:
                    180:        while ((ch = getopt(argc, argv, optstr)) != -1) {
                    181:                switch (ch) {
1.10      martijn   182:                case 'A':
                    183:                        authkey = optarg;
                    184:                        authkeylen = strlen(authkey);
                    185:                        authkeylevel = USM_KEY_PASSWORD;
                    186:                        break;
                    187:                case 'a':
                    188:                        if (strcasecmp(optarg, "MD5") == 0)
                    189:                                md = EVP_md5();
                    190:                        else if (strcasecmp(optarg, "SHA") == 0)
                    191:                                md = EVP_sha1();
                    192:                        else if (strcasecmp(optarg, "SHA-224") == 0)
                    193:                                md = EVP_sha224();
                    194:                        else if (strcasecmp(optarg, "SHA-256") == 0)
                    195:                                md = EVP_sha256();
                    196:                        else if (strcasecmp(optarg, "SHA-384") == 0)
                    197:                                md = EVP_sha384();
                    198:                        else if (strcasecmp(optarg, "SHA-512") == 0)
                    199:                                md = EVP_sha512();
                    200:                        else
                    201:                                errx(1, "Invalid authentication protocol "
                    202:                                    "specified after -a flag: %s", optarg);
                    203:                        break;
1.1       martijn   204:                case 'c':
                    205:                        community = optarg;
                    206:                        break;
1.9       martijn   207:                case 'E':
                    208:                        ctxengineid = snmpc_hex2bin(optarg,
                    209:                            &ctxengineidlen);
                    210:                        if (ctxengineid == NULL) {
                    211:                                if (errno == EINVAL)
                    212:                                        errx(1, "Bad engine ID value "
                    213:                                            "after -3E flag.");
                    214:                                err(1, "-3E");
                    215:                        }
                    216:                        break;
                    217:                case 'e':
                    218:                        secengineid = snmpc_hex2bin(optarg,
                    219:                            &secengineidlen);
                    220:                        if (secengineid == NULL) {
                    221:                                if (errno == EINVAL)
                    222:                                        errx(1, "Bad engine ID value "
                    223:                                            "after -3e flag.");
                    224:                                err(1, "-3e");
                    225:                        }
                    226:                        break;
1.11      martijn   227:                case 'K':
                    228:                        privkey = snmpc_hex2bin(optarg, &privkeylen);
                    229:                        if (privkey == NULL) {
                    230:                                if (errno == EINVAL)
                    231:                                        errx(1, "Bad key value after "
                    232:                                            "-3K flag.");
                    233:                                errx(1, "-3K");
                    234:                        }
                    235:                        privkeylevel = USM_KEY_LOCALIZED;
                    236:                                break;
1.10      martijn   237:                case 'k':
                    238:                        authkey = snmpc_hex2bin(optarg, &authkeylen);
                    239:                        if (authkey == NULL) {
                    240:                                if (errno == EINVAL)
                    241:                                        errx(1, "Bad key value after -k flag.");
                    242:                                err(1, "-k");
                    243:                        }
                    244:                        authkeylevel = USM_KEY_LOCALIZED;
                    245:                        break;
                    246:                case 'l':
                    247:                        if (strcasecmp(optarg, "noAuthNoPriv") == 0)
                    248:                                seclevel = SNMP_MSGFLAG_REPORT;
                    249:                        else if (strcasecmp(optarg, "authNoPriv") == 0)
                    250:                                seclevel = SNMP_MSGFLAG_AUTH |
                    251:                                    SNMP_MSGFLAG_REPORT;
1.11      martijn   252:                        else if (strcasecmp(optarg, "authPriv") == 0)
                    253:                                seclevel = SNMP_MSGFLAG_AUTH |
                    254:                                    SNMP_MSGFLAG_PRIV | SNMP_MSGFLAG_REPORT;
1.10      martijn   255:                        else
                    256:                                errx(1, "Invalid security level specified "
                    257:                                    "after -l flag: %s", optarg);
                    258:                        break;
1.9       martijn   259:                case 'n':
                    260:                        ctxname = optarg;
                    261:                        break;
1.1       martijn   262:                case 'r':
                    263:                        if ((retries = strtonum(optarg, 0, INT_MAX,
                    264:                            &errstr)) == 0) {
                    265:                                if (errstr != NULL)
                    266:                                        errx(1, "-r: %s argument", errstr);
                    267:                        }
                    268:                        break;
                    269:                case 't':
                    270:                        if ((timeout = strtonum(optarg, 1, INT_MAX,
                    271:                            &errstr)) == 0) {
                    272:                                if (errstr != NULL)
                    273:                                        errx(1, "-t: %s argument", errstr);
                    274:                        }
                    275:                        break;
1.9       martijn   276:                case 'u':
                    277:                        user = optarg;
                    278:                        break;
1.1       martijn   279:                case 'v':
                    280:                        if (strcmp(optarg, "1") == 0)
                    281:                                version = SNMP_V1;
                    282:                        else if (strcmp(optarg, "2c") == 0)
                    283:                                version = SNMP_V2C;
1.9       martijn   284:                        else if (strcmp(optarg, "3") == 0)
                    285:                                version = SNMP_V3;
1.1       martijn   286:                        else
                    287:                                errc(1, EINVAL, "-v");
                    288:                        break;
                    289:                case 'C':
                    290:                        for (i = 0; i < strlen(optarg); i++) {
                    291:                                switch (optarg[i]) {
                    292:                                case 'c':
                    293:                                        if (strcmp(snmp_app->name, "walk") &&
                    294:                                            strcmp(snmp_app->name, "bulkwalk"))
                    295:                                                usage();
                    296:                                        walk_check_increase = 0;
                    297:                                        break;
1.19      martijn   298:                                case 'h':
                    299:                                        if (strcmp(snmp_app->name, "df"))
                    300:                                                usage();
                    301:                                        print_human = 1;
                    302:                                        break;
1.1       martijn   303:                                case 'i':
                    304:                                        if (strcmp(snmp_app->name, "walk") &&
                    305:                                            strcmp(snmp_app->name, "bulkwalk"))
                    306:                                                usage();
                    307:                                        walk_include_oid = 1;
                    308:                                        break;
                    309:                                case 'n':
                    310:                                        if (strcmp(snmp_app->name, "bulkget") &&
                    311:                                            strcmp(snmp_app->name, "bulkwalk"))
                    312:                                                usage();
                    313:                                        errno = 0;
                    314:                                        non_repeaters = strtol(&optarg[i + 1],
                    315:                                            &strtolp, 10);
                    316:                                        if (non_repeaters < 0 ||
                    317:                                            errno == ERANGE) {
                    318:                                                if (non_repeaters < 0)
                    319:                                                        errx(1, "%s%s",
                    320:                                                            "-Cn: too small ",
                    321:                                                            "argument");
                    322:                                                else
                    323:                                                        errx(1, "%s%s",
                    324:                                                            "-Cn: too large",
                    325:                                                            "argument");
                    326:                                        } else if (&optarg[i + 1] == strtolp)
                    327:                                                errx(1, "-Cn invalid argument");
                    328:                                        i = strtolp - optarg - 1;
                    329:                                        break;
                    330:                                case 'p':
                    331:                                        if (strcmp(snmp_app->name, "walk") &&
                    332:                                            strcmp(snmp_app->name, "bulkwalk"))
                    333:                                                usage();
                    334:                                        print_summary = 1;
                    335:                                        break;
                    336:                                case 'r':
                    337:                                        if (strcmp(snmp_app->name, "bulkget") &&
1.19      martijn   338:                                            strcmp(snmp_app->name, "bulkwalk") &&
                    339:                                            strcmp(snmp_app->name, "df"))
1.1       martijn   340:                                                usage();
                    341:                                        errno = 0;
                    342:                                        max_repetitions = strtol(&optarg[i + 1],
                    343:                                            &strtolp, 10);
                    344:                                        if (max_repetitions < 0 ||
                    345:                                            errno == ERANGE) {
                    346:                                                if (max_repetitions < 0)
                    347:                                                        errx(1, "%s%s",
                    348:                                                            "-Cr: too small ",
                    349:                                                            "argument");
                    350:                                                else
                    351:                                                        errx(1, "%s%s",
                    352:                                                            "-Cr: too large",
                    353:                                                            "argument");
                    354:                                        } else if (&optarg[i + 1] == strtolp)
                    355:                                                errx(1, "-Cr invalid argument");
                    356:                                        i = strtolp - optarg - 1;
                    357:                                        break;
1.18      martijn   358:                                case 's':
                    359:                                        if (strcmp(snmp_app->name, "walk") &&
                    360:                                            strcmp(snmp_app->name, "bulkwalk"))
                    361:                                                usage();
                    362:                                        if ((walk_skip = recallocarray(
                    363:                                            walk_skip, walk_skip_len,
                    364:                                            walk_skip_len + 1,
                    365:                                            sizeof(*walk_skip))) == NULL)
                    366:                                                errx(1, "malloc");
                    367:                                        if (smi_string2oid(argv[optind],
                    368:                                            &(walk_skip[walk_skip_len])) != 0)
                    369:                                                errx(1, "%s: %s",
                    370:                                                    "Unknown Object Identifier",
                    371:                                                    argv[optind]);
                    372:                                        walk_skip_len++;
                    373:                                        optind++;
                    374:                                        break;
1.1       martijn   375:                                case 't':
                    376:                                        if (strcmp(snmp_app->name, "walk"))
                    377:                                                usage();
                    378:                                        print_time = 1;
                    379:                                        break;
                    380:                                case 'E':
                    381:                                        if (strcmp(snmp_app->name, "walk"))
                    382:                                                usage();
                    383:                                        if (smi_string2oid(argv[optind],
                    384:                                            &walk_end) != 0)
                    385:                                                errx(1, "%s: %s",
                    386:                                                    "Unknown Object Identifier",
                    387:                                                    argv[optind]);
                    388:                                        optind++;
                    389:                                        continue;
                    390:                                case 'I':
                    391:                                        if (strcmp(snmp_app->name, "walk"))
                    392:                                                usage();
                    393:                                        walk_fallback_oid = 0;
                    394:                                        break;
                    395:                                default:
                    396:                                        usage();
                    397:                                }
                    398:                                if (optarg[i] == 'E')
                    399:                                        break;
                    400:                        }
                    401:                        break;
                    402:                case 'O':
                    403:                        for (i = 0; i < strlen(optarg); i++) {
                    404:                                if (strcmp(snmp_app->name, "mibtree") == 0 &&
                    405:                                    optarg[i] != 'f' && optarg[i] != 'n' &&
                    406:                                    optarg[i] != 'S')
                    407:                                                usage();
                    408:                                switch (optarg[i]) {
                    409:                                case 'a':
                    410:                                        output_string = smi_os_ascii;
                    411:                                        break;
                    412:                                case 'f':
                    413:                                        oid_lookup = smi_oidl_full;
                    414:                                        break;
                    415:                                case 'n':
                    416:                                        oid_lookup = smi_oidl_numeric;
                    417:                                        break;
                    418:                                case 'q':
                    419:                                        print_equals = 0;
                    420:                                        smi_print_hint = 0;
                    421:                                        break;
                    422:                                case 'v':
1.2       deraadt   423:                                        print_varbind_only = 1;
1.1       martijn   424:                                        break;
                    425:                                case 'x':
                    426:                                        output_string = smi_os_hex;
                    427:                                        break;
                    428:                                case 'S':
                    429:                                        oid_lookup = smi_oidl_short;
                    430:                                        break;
                    431:                                case 'Q':
                    432:                                        smi_print_hint = 0;
                    433:                                        break;
                    434:                                default:
                    435:                                        usage();
                    436:                                }
                    437:                        }
                    438:                        break;
1.11      martijn   439:                case 'X':
                    440:                        privkey = optarg;
                    441:                        privkeylen = strlen(privkey);
                    442:                        privkeylevel = USM_KEY_PASSWORD;
                    443:                        break;
                    444:                case 'x':
                    445:                        if (strcasecmp(optarg, "DES") == 0)
                    446:                                cipher = EVP_des_cbc();
                    447:                        else if (strcasecmp(optarg, "AES") == 0)
                    448:                                cipher = EVP_aes_128_cfb128();
                    449:                        else
                    450:                                errx(1, "Invalid privacy protocol "
                    451:                                    "specified after -3x flag: %s",
                    452:                                    optarg);
                    453:                        break;
1.9       martijn   454:                case 'Z':
                    455:                        boots = strtoll(optarg, &strtolp, 10);
                    456:                        if (boots < 0 || strtolp == optarg || strtolp[0] != ',')
                    457:                                usage();
                    458:                        strtolp++;
                    459:                        time = strtoll(strtolp, &strtolp, 10);
                    460:                        if (boots < 0 || strtolp == optarg)
                    461:                                usage();
                    462:                        zflag = 1;
                    463:                        break;
1.1       martijn   464:                default:
                    465:                        usage();
                    466:                }
                    467:        }
                    468:        argc -= optind;
                    469:        argv += optind;
                    470:
1.9       martijn   471:        if (version == SNMP_V3) {
                    472:                /* Setup USM */
                    473:                if (user == NULL || user[0] == '\0')
                    474:                        errx(1, "No securityName specified");
                    475:                if ((sec = usm_init(user, strlen(user))) == NULL)
                    476:                        err(1, "usm_init");
1.10      martijn   477:                if (seclevel & SNMP_MSGFLAG_AUTH) {
                    478:                        if (md == NULL)
                    479:                                md = EVP_md5();
                    480:                        if (authkey == NULL)
                    481:                                errx(1, "No authKey or authPassword specified");
                    482:                        if (usm_setauth(sec, md, authkey, authkeylen,
                    483:                            authkeylevel) == -1)
                    484:                                err(1, "Can't set authkey");
                    485:                }
1.11      martijn   486:                if (seclevel & SNMP_MSGFLAG_PRIV) {
                    487:                        if (cipher == NULL)
                    488:                                cipher = EVP_des_cbc();
                    489:                        if (privkey == NULL)
                    490:                                errx(1, "No privKey or privPassword specified");
                    491:                        if (usm_setpriv(sec, cipher, privkey, privkeylen,
                    492:                            privkeylevel) == -1)
                    493:                                err(1, "Can't set authkey");
                    494:                }
1.9       martijn   495:                if (secengineid != NULL) {
                    496:                        if (usm_setengineid(sec, secengineid,
                    497:                            secengineidlen) == -1)
                    498:                                err(1, "Can't set secengineid");
                    499:                }
                    500:                if (zflag)
                    501:                        if (usm_setbootstime(sec, boots, time) == -1)
                    502:                                err(1, "Can't set boots/time");
                    503:                v3 = snmp_v3_init(seclevel, ctxname, ctxname == NULL ? 0 :
                    504:                    strlen(ctxname), sec);
                    505:                if (v3 == NULL)
                    506:                        err(1, "snmp_v3_init");
                    507:                if (ctxengineid != NULL) {
                    508:                        if (snmp_v3_setengineid(v3, ctxengineid,
                    509:                            ctxengineidlen) == -1)
                    510:                                err(1, "Can't set ctxengineid");
                    511:                }
                    512:        }
                    513:
                    514:
1.1       martijn   515:        return snmp_app->exec(argc, argv);
                    516: }
                    517:
                    518: int
                    519: snmpc_get(int argc, char *argv[])
                    520: {
                    521:        struct ber_oid *oid;
                    522:        struct ber_element *pdu, *varbind;
                    523:        struct snmp_agent *agent;
                    524:        int errorstatus, errorindex;
                    525:        int i;
1.9       martijn   526:        int class;
                    527:        unsigned type;
1.15      martijn   528:        char *hint = NULL;
1.1       martijn   529:
                    530:        if (argc < 2)
                    531:                usage();
                    532:
1.8       martijn   533:        if ((agent = snmpc_connect(argv[0], "161")) == NULL)
1.1       martijn   534:                err(1, "%s", snmp_app->name);
                    535:        agent->timeout = timeout;
                    536:        agent->retries = retries;
                    537:
                    538:        if (pledge("stdio", NULL) == -1)
                    539:                err(1, "pledge");
                    540:        argc--;
                    541:        argv++;
                    542:
                    543:        oid = reallocarray(NULL, argc, sizeof(*oid));
1.3       deraadt   544:        if (oid == NULL)
                    545:                err(1, "malloc");
1.1       martijn   546:        for (i = 0; i < argc; i++) {
                    547:                if (smi_string2oid(argv[i], &oid[i]) == -1)
1.12      semarie   548:                        errx(1, "%s: Unknown object identifier", argv[i]);
1.1       martijn   549:        }
                    550:        if (strcmp(snmp_app->name, "getnext") == 0) {
                    551:                if ((pdu = snmp_getnext(agent, oid, argc)) == NULL)
                    552:                        err(1, "getnext");
                    553:        } else if (strcmp(snmp_app->name, "bulkget") == 0) {
                    554:                if (version < SNMP_V2C)
                    555:                        errx(1, "Cannot send V2 PDU on V1 session");
                    556:                if (non_repeaters > argc)
                    557:                        errx(1, "need more objects than -Cn<num>");
                    558:                if ((pdu = snmp_getbulk(agent, oid, argc, non_repeaters,
                    559:                    max_repetitions)) == NULL)
                    560:                        err(1, "bulkget");
                    561:        } else {
                    562:                if ((pdu = snmp_get(agent, oid, argc)) == NULL)
                    563:                        err(1, "get");
                    564:        }
                    565:
1.16      tb        566:        (void) ober_scanf_elements(pdu, "t{Sdd{e", &class, &type, &errorstatus,
1.9       martijn   567:            &errorindex, &varbind);
1.15      martijn   568:        if (errorstatus != 0) {
                    569:                if (errorindex >= 1 && errorindex <= argc)
                    570:                        hint = argv[errorindex - 1];
                    571:                snmpc_printerror((enum snmp_error) errorstatus, varbind,
                    572:                    errorindex, hint);
                    573:        }
1.1       martijn   574:
1.9       martijn   575:        if (class == BER_CLASS_CONTEXT && type == SNMP_C_REPORT)
                    576:                printf("Received report:\n");
1.1       martijn   577:        for (; varbind != NULL; varbind = varbind->be_next) {
                    578:                if (!snmpc_print(varbind))
                    579:                        err(1, "Can't print response");
                    580:        }
1.16      tb        581:        ober_free_elements(pdu);
1.1       martijn   582:        snmp_free_agent(agent);
                    583:        return 0;
                    584: }
                    585:
                    586: int
                    587: snmpc_walk(int argc, char *argv[])
                    588: {
                    589:        struct ber_oid oid, loid, noid;
                    590:        struct ber_element *pdu, *varbind, *value;
                    591:        struct timespec start, finish;
                    592:        struct snmp_agent *agent;
                    593:        const char *oids;
1.18      martijn   594:        int n = 0, prev_cmp, skip_cmp;
1.1       martijn   595:        int errorstatus, errorindex;
1.9       martijn   596:        int class;
1.18      martijn   597:        size_t i;
1.9       martijn   598:        unsigned type;
1.1       martijn   599:
                    600:        if (strcmp(snmp_app->name, "bulkwalk") == 0 && version < SNMP_V2C)
                    601:                errx(1, "Cannot send V2 PDU on V1 session");
                    602:        if (argc < 1 || argc > 2)
                    603:                usage();
                    604:        oids = argc == 1 ? mib : argv[1];
                    605:
1.8       martijn   606:        if ((agent = snmpc_connect(argv[0], "161"))== NULL)
1.1       martijn   607:                err(1, "%s", snmp_app->name);
                    608:        agent->timeout = timeout;
                    609:        agent->retries = retries;
                    610:        if (pledge("stdio", NULL) == -1)
                    611:                err(1, "pledge");
                    612:
                    613:        if (smi_string2oid(oids, &oid) == -1)
                    614:                errx(1, "%s: Unknown object identifier", oids);
                    615:        bcopy(&oid, &noid, sizeof(noid));
                    616:        if (print_time)
                    617:                clock_gettime(CLOCK_MONOTONIC, &start);
                    618:
                    619:        if (walk_include_oid) {
                    620:                if ((pdu = snmp_get(agent, &oid, 1)) == NULL)
                    621:                        err(1, "%s", snmp_app->name);
                    622:
1.16      tb        623:                (void) ober_scanf_elements(pdu, "t{Sdd{e", &class, &type,
1.9       martijn   624:                    &errorstatus, &errorindex, &varbind);
1.1       martijn   625:                if (errorstatus != 0)
1.15      martijn   626:                        snmpc_printerror((enum snmp_error) errorstatus, varbind,
                    627:                            errorindex, oids);
1.1       martijn   628:
1.9       martijn   629:                if (class == BER_CLASS_CONTEXT && type == SNMP_C_REPORT)
                    630:                        printf("Received report:\n");
1.1       martijn   631:                if (!snmpc_print(varbind))
                    632:                        err(1, "Can't print response");
1.16      tb        633:                ober_free_element(pdu);
1.9       martijn   634:                if (class == BER_CLASS_CONTEXT && type == SNMP_C_REPORT)
                    635:                        return 1;
1.1       martijn   636:                n++;
                    637:        }
                    638:        while (1) {
1.18      martijn   639:                for (i = 0; i < walk_skip_len; i++) {
                    640:                        skip_cmp = ober_oid_cmp(&(walk_skip[i]), &noid);
                    641:                        if (skip_cmp == 0 || skip_cmp == 2) {
                    642:                                bcopy(&(walk_skip[i]), &noid, sizeof(noid));
                    643:                                noid.bo_id[noid.bo_n -1]++;
                    644:                                break;
                    645:                        }
                    646:                }
1.1       martijn   647:                bcopy(&noid, &loid, sizeof(loid));
                    648:                if (strcmp(snmp_app->name, "bulkwalk") == 0) {
                    649:                        if ((pdu = snmp_getbulk(agent, &noid, 1,
                    650:                            non_repeaters, max_repetitions)) == NULL)
                    651:                                err(1, "bulkwalk");
                    652:                } else {
                    653:                        if ((pdu = snmp_getnext(agent, &noid, 1)) == NULL)
                    654:                                err(1, "walk");
                    655:                }
                    656:
1.16      tb        657:                (void) ober_scanf_elements(pdu, "t{Sdd{e", &class, &type,
1.9       martijn   658:                    &errorstatus, &errorindex, &varbind);
1.1       martijn   659:                if (errorstatus != 0) {
1.15      martijn   660:                        snmpc_printerror((enum snmp_error) errorstatus, varbind,
                    661:                            errorindex, NULL);
1.1       martijn   662:                }
                    663:
1.9       martijn   664:                if (class == BER_CLASS_CONTEXT && type == SNMP_C_REPORT)
                    665:                        printf("Received report:\n");
1.2       deraadt   666:                for (; varbind != NULL; varbind = varbind->be_next) {
1.16      tb        667:                        (void) ober_scanf_elements(varbind, "{oe}", &noid,
1.1       martijn   668:                            &value);
                    669:                        if (value->be_class == BER_CLASS_CONTEXT &&
                    670:                            value->be_type == BER_TYPE_EOC)
                    671:                                break;
1.18      martijn   672:                        for (i = 0; i < walk_skip_len; i++) {
                    673:                                skip_cmp = ober_oid_cmp(&(walk_skip[i]), &noid);
                    674:                                if (skip_cmp == 0 || skip_cmp == 2)
                    675:                                        break;
                    676:                        }
                    677:                        if (i < walk_skip_len)
                    678:                                continue;
1.16      tb        679:                        prev_cmp = ober_oid_cmp(&loid, &noid);
1.1       martijn   680:                        if (walk_check_increase && prev_cmp == -1)
                    681:                                errx(1, "OID not increasing");
1.16      tb        682:                        if (prev_cmp == 0 || ober_oid_cmp(&oid, &noid) != 2)
1.1       martijn   683:                                break;
                    684:                        if (walk_end.bo_n != 0 &&
1.16      tb        685:                            ober_oid_cmp(&walk_end, &noid) != -1)
1.1       martijn   686:                                break;
                    687:
                    688:                        if (!snmpc_print(varbind))
                    689:                                err(1, "Can't print response");
                    690:                        n++;
                    691:                }
1.16      tb        692:                ober_free_elements(pdu);
1.9       martijn   693:                if (class == BER_CLASS_CONTEXT && type == SNMP_C_REPORT)
                    694:                        return 1;
1.1       martijn   695:                if (varbind != NULL)
                    696:                        break;
                    697:        }
                    698:        if (walk_fallback_oid && n == 0) {
                    699:                if ((pdu = snmp_get(agent, &oid, 1)) == NULL)
                    700:                        err(1, "%s", snmp_app->name);
                    701:
1.16      tb        702:                (void) ober_scanf_elements(pdu, "t{Sdd{e", &class, &type,
1.9       martijn   703:                    &errorstatus, &errorindex, &varbind);
1.1       martijn   704:                if (errorstatus != 0)
1.15      martijn   705:                        snmpc_printerror((enum snmp_error) errorstatus, varbind,
                    706:                            errorindex, oids);
1.1       martijn   707:
1.9       martijn   708:                if (class == BER_CLASS_CONTEXT && type == SNMP_C_REPORT)
                    709:                        printf("Received report:\n");
1.1       martijn   710:                if (!snmpc_print(varbind))
                    711:                        err(1, "Can't print response");
1.16      tb        712:                ober_free_element(pdu);
1.9       martijn   713:                if (class == BER_CLASS_CONTEXT && type == SNMP_C_REPORT)
                    714:                        return 1;
1.1       martijn   715:                n++;
                    716:        }
                    717:        if (print_time)
                    718:                clock_gettime(CLOCK_MONOTONIC, &finish);
                    719:        if (print_summary)
                    720:                printf("Variables found: %d\n", n);
                    721:        if (print_time) {
                    722:                if ((finish.tv_nsec -= start.tv_nsec) < 0) {
                    723:                        finish.tv_sec -= 1;
                    724:                        finish.tv_nsec += 1000000000;
                    725:                }
                    726:                finish.tv_sec -= start.tv_sec;
                    727:                fprintf(stderr, "Total traversal time: %lld.%09ld seconds\n",
                    728:                    finish.tv_sec, finish.tv_nsec);
                    729:        }
                    730:        snmp_free_agent(agent);
                    731:        return 0;
                    732: }
                    733:
                    734: int
1.13      martijn   735: snmpc_set(int argc, char *argv[])
                    736: {
                    737:        struct snmp_agent *agent;
                    738:        struct ber_element *pdu, *varbind;
                    739:        int errorstatus, errorindex;
                    740:        int class;
                    741:        unsigned type;
1.15      martijn   742:        char *hint = NULL;
1.13      martijn   743:
                    744:        if (argc < 4)
                    745:                usage();
                    746:        if ((agent = snmpc_connect(argv[0], "161")) == NULL)
                    747:                err(1, "%s", snmp_app->name);
                    748:        argc--;
                    749:        argv++;
                    750:
                    751:        if (pledge("stdio", NULL) == -1)
                    752:                err(1, "pledge");
                    753:
1.15      martijn   754:        if ((pdu = snmp_set(agent, snmpc_varbindparse(argc, argv))) == NULL)
                    755:                err(1, "set");
1.13      martijn   756:
1.16      tb        757:        (void) ober_scanf_elements(pdu, "t{Sdd{e", &class, &type, &errorstatus,
1.13      martijn   758:            &errorindex, &varbind);
1.15      martijn   759:        if (errorstatus != 0) {
                    760:                if (errorindex >= 1 && errorindex <= argc / 3)
                    761:                        hint = argv[(errorindex - 1) * 3];
                    762:                snmpc_printerror((enum snmp_error) errorstatus, varbind,
                    763:                    errorindex, hint);
                    764:        }
1.13      martijn   765:
                    766:        if (class == BER_CLASS_CONTEXT && type == SNMP_C_REPORT)
                    767:                printf("Received report:\n");
                    768:        for (; varbind != NULL; varbind = varbind->be_next) {
                    769:                if (!snmpc_print(varbind))
                    770:                        err(1, "Can't print response");
                    771:        }
1.16      tb        772:        ober_free_elements(pdu);
1.13      martijn   773:        snmp_free_agent(agent);
                    774:        return 0;
                    775: }
                    776:
                    777: int
1.1       martijn   778: snmpc_trap(int argc, char *argv[])
                    779: {
                    780:        struct snmp_agent *agent;
                    781:        struct timespec ts;
1.13      martijn   782:        struct ber_oid trapoid;
1.1       martijn   783:        const char *errstr = NULL;
                    784:        long long lval;
                    785:
                    786:        if (version == SNMP_V1)
                    787:                errx(1, "trap is not supported for snmp v1");
1.31      martijn   788:
                    789:        if (argc < 3)
                    790:                usage();
1.1       martijn   791:
1.8       martijn   792:        if ((agent = snmpc_connect(argv[0], "162")) == NULL)
1.1       martijn   793:                err(1, "%s", snmp_app->name);
                    794:
                    795:        if (pledge("stdio", NULL) == -1)
                    796:                err(1, "pledge");
                    797:
                    798:        if (argv[1][0] == '\0') {
                    799:                if (clock_gettime(CLOCK_UPTIME, &ts) == -1)
                    800:                        err(1, "clock_gettime");
                    801:        } else {
                    802:                lval = strtonum(argv[1], 0, LLONG_MAX, &errstr);
                    803:                if (errstr != NULL)
                    804:                        errx(1, "Bad value notation (%s)", argv[1]);
                    805:                ts.tv_sec = lval / 100;
                    806:                ts.tv_nsec = (lval % 100) * 10000000;
                    807:        }
                    808:        if (smi_string2oid(argv[2], &trapoid) == -1)
                    809:                errx(1, "Invalid oid: %s\n", argv[2]);
                    810:
                    811:        argc -= 3;
                    812:        argv += 3;
                    813:
1.13      martijn   814:        snmp_trap(agent, &ts, &trapoid, snmpc_varbindparse(argc, argv));
1.19      martijn   815:
                    816:        return 0;
                    817: }
                    818:
                    819: #define INCR_NEXTTAB(x) ((x + 8) & ~7)
                    820: #define NEXTTAB(x) (8 - (x & 7))
                    821: int
                    822: snmpc_df(int argc, char *argv[])
                    823: {
                    824:        struct snmpc_df {
                    825:                uint32_t index;
1.29      martijn   826:                char *descr;
                    827:                int descrwidth;
1.19      martijn   828:                /* Theoretical maximum for 2 32 bit values multiplied */
                    829:                char size[21];
                    830:                char used[21];
                    831:                char avail[21];
                    832:                char proc[5];
                    833:        } *df = NULL;
                    834:        struct ber_oid descroid = {{ 1, 3, 6, 1, 2, 1, 25, 2, 3, 1, 3 }, 11};
                    835:        struct ber_oid unitsoid = {{ 1, 3, 6, 1, 2, 1, 25, 2, 3, 1, 4 }, 11};
                    836:        struct ber_oid sizeoid = {{ 1, 3, 6, 1, 2, 1, 25, 2, 3, 1, 5 }, 11};
                    837:        struct ber_oid usedoid = {{ 1, 3, 6, 1, 2, 1, 25, 2, 3, 1, 6 }, 11};
                    838:        struct ber_oid oid, *reqoid;
1.29      martijn   839:        char oids[SNMP_MAX_OID_STRLEN];
                    840:        struct ber_element *pdu, *varbind, *elm;
1.19      martijn   841:        struct snmp_agent *agent;
                    842:        int errorstatus, errorindex;
                    843:        int class;
                    844:        size_t i, j, rows = 0;
                    845:        unsigned type;
                    846:        char *string;
                    847:        int descrlen = 0, sizelen = 0, usedlen = 0, availlen = 0, proclen = 0;
                    848:        int len;
                    849:        long long units, size, used;
                    850:        int fmtret;
                    851:
                    852:        if (argc != 1)
                    853:                usage();
                    854:
                    855:        if ((agent = snmpc_connect(argv[0], "161")) == NULL)
                    856:                err(1, "%s", snmp_app->name);
                    857:        agent->timeout = timeout;
                    858:        agent->retries = retries;
                    859:
                    860:        if (pledge("stdio", NULL) == -1)
                    861:                err(1, "pledge");
                    862:
                    863:        descrlen = sizeof("Description") - 1;
                    864:        sizelen = sizeof("Size") - 1;
                    865:        usedlen = sizeof("Used") - 1;
                    866:        availlen = sizeof("Available") - 1;
                    867:        proclen = sizeof("Used%") - 1;
                    868:
                    869:        bcopy(&descroid, &oid, sizeof(descroid));
                    870:
                    871:        i = 0;
                    872:        while(1) {
                    873:                if (version < SNMP_V2C) {
                    874:                        if ((pdu = snmp_getnext(agent, &oid, 1)) == NULL)
                    875:                                err(1, "df");
                    876:                } else {
                    877:                        if ((pdu = snmp_getbulk(agent, &oid, 1, 0,
                    878:                            max_repetitions)) == NULL)
                    879:                                err(1, "df");
                    880:                }
                    881:
                    882:                (void) ober_scanf_elements(pdu, "t{Sdd{e", &class, &type,
                    883:                    &errorstatus, &errorindex, &varbind);
                    884:                if (errorstatus != 0)
                    885:                        snmpc_printerror((enum snmp_error) errorstatus, varbind,
                    886:                            errorindex, NULL);
                    887:
                    888:                if (class == BER_CLASS_CONTEXT && type == SNMP_C_REPORT) {
                    889:                        printf("Received report:\n");
                    890:                        for (; varbind != NULL; varbind = varbind->be_next) {
                    891:                                if (!snmpc_print(varbind))
                    892:                                        err(1, "Can't print response");
                    893:                        }
                    894:                        return 1;
                    895:                }
                    896:                for (; varbind != NULL; varbind = varbind->be_next) {
1.29      martijn   897:                        if (ober_scanf_elements(varbind, "{os", &oid,
                    898:                            &string) == -1 ||
                    899:                            ober_oid_cmp(&descroid, &oid) != 2)
1.19      martijn   900:                                break;
                    901:                        rows++;
                    902:                }
                    903:                if ((df = reallocarray(df, rows, sizeof(*df))) == NULL)
                    904:                        err(1, "malloc");
                    905:                (void) ober_scanf_elements(pdu, "{SSS{e", &varbind);
                    906:                for (; i < rows; varbind = varbind->be_next, i++) {
1.29      martijn   907:                        if (ober_scanf_elements(varbind, "{oe", &oid,
                    908:                            &elm) == -1) {
1.19      martijn   909:                                i--;
                    910:                                rows--;
                    911:                                continue;
                    912:                        }
1.29      martijn   913:                        if (ober_oid_cmp(&descroid, &oid) != 2)
                    914:                                break;
1.19      martijn   915:                        df[i].index = oid.bo_id[oid.bo_n - 1];
1.29      martijn   916:                        if ((df[i].descr = smi_print_element(&oid, elm, 0,
                    917:                            smi_os_ascii, 0, utf8)) == NULL) {
                    918:                                smi_oid2string(&oid, oids, sizeof(oids),
                    919:                                    oid_lookup);
                    920:                                warn("df: can't print oid %s", oids);
                    921:                                i--;
                    922:                                rows--;
                    923:                                continue;
                    924:                        }
                    925:                        if ((df[i].descrwidth =
                    926:                            (int) snmpc_mbswidth(df[i].descr)) == -1)
                    927:                                err(1, "df: invalid hrStorageDescr");
                    928:                        if (df[i].descrwidth > descrlen)
                    929:                                descrlen = df[i].descrwidth;
1.19      martijn   930:                }
                    931:                ober_free_elements(pdu);
                    932:                if (varbind != NULL)
                    933:                        break;
                    934:        }
                    935:
                    936:        if (max_repetitions < 3)
                    937:                max_repetitions = 3;
                    938:        if ((reqoid = reallocarray(NULL, max_repetitions, sizeof(*reqoid))) == NULL)
                    939:                err(1, "malloc");
                    940:        for (i = 0; i < rows;) {
                    941:                for (j = 0; i + j < rows && j < (size_t)max_repetitions / 3;
                    942:                    j++) {
                    943:                        bcopy(&unitsoid, &(reqoid[(j * 3) + 0]),
                    944:                            sizeof(unitsoid));
                    945:                        reqoid[(j * 3) + 0].bo_id[
                    946:                            reqoid[(j * 3) + 0].bo_n++] = df[i + j].index;
                    947:                        bcopy(&sizeoid, &(reqoid[(j * 3) + 1]),
                    948:                            sizeof(sizeoid));
                    949:                        reqoid[(j * 3) + 1].bo_id[
                    950:                            reqoid[(j * 3) + 1].bo_n++] = df[i + j].index;
                    951:                        bcopy(&usedoid, &(reqoid[(j * 3) + 2]),
                    952:                            sizeof(usedoid));
                    953:                        reqoid[(j * 3) + 2].bo_id[
                    954:                            reqoid[(j * 3) + 2].bo_n++] = df[i + j].index;
                    955:                }
                    956:                if ((pdu = snmp_get(agent, reqoid, j * 3)) == NULL)
                    957:                        err(1, "df");
                    958:                (void) ober_scanf_elements(pdu, "t{Sdd{e", &class, &type,
                    959:                    &errorstatus, &errorindex, &varbind);
                    960:                if (errorstatus != 0)
                    961:                        snmpc_printerror((enum snmp_error) errorstatus, varbind,
                    962:                            errorindex, NULL);
                    963:                if (class == BER_CLASS_CONTEXT && type == SNMP_C_REPORT) {
                    964:                        printf("Received report:\n");
                    965:                        for (; varbind != NULL; varbind = varbind->be_next) {
                    966:                                if (!snmpc_print(varbind))
                    967:                                        err(1, "Can't print response");
                    968:                        }
                    969:                }
                    970:                for (j = 0; varbind != NULL; i++) {
                    971:                        if (ober_scanf_elements(varbind, "{oi}{oi}{oi}",
                    972:                            &(reqoid[0]), &units, &(reqoid[1]), &size,
                    973:                            &(reqoid[2]), &used, &varbind) == -1) {
                    974:                                break;
                    975:                        }
                    976:                        varbind = varbind->be_next->be_next->be_next;
                    977:
                    978:                        unitsoid.bo_id[unitsoid.bo_n++] = df[i].index;
                    979:                        if (ober_oid_cmp(&unitsoid, &(reqoid[0])) != 0) {
                    980:                                warnx("df: received invalid object");
                    981:                                break;
                    982:                        }
                    983:                        unitsoid.bo_n--;
                    984:                        sizeoid.bo_id[sizeoid.bo_n++] = df[i].index;
                    985:                        if (ober_oid_cmp(&sizeoid, &(reqoid[1])) != 0) {
                    986:                                warnx("df: received invalid object");
                    987:                                break;
                    988:                        }
                    989:                        sizeoid.bo_n--;
                    990:                        usedoid.bo_id[usedoid.bo_n++] = df[i].index;
                    991:                        if (ober_oid_cmp(&usedoid, &(reqoid[2])) != 0) {
                    992:                                warnx("df: received invalid object");
                    993:                                break;
                    994:                        }
                    995:                        usedoid.bo_n--;
                    996:                        if (print_human)
                    997:                                fmtret = fmt_scaled((units * size), df[i].size);
                    998:                        if (!print_human || fmtret == -1)
                    999:                                snprintf(df[i].size, sizeof(df[i].size), "%lld",
                   1000:                                    (units * size) / 1024);
                   1001:                        len = (int) strlen(df[i].size);
                   1002:                        if (len > sizelen)
                   1003:                                sizelen = len;
                   1004:                        if (print_human)
                   1005:                                fmtret = fmt_scaled(units * used, df[i].used);
                   1006:                        if (!print_human || fmtret == -1)
                   1007:                                snprintf(df[i].used, sizeof(df[i].used), "%lld",
                   1008:                                    (units * used) / 1024);
                   1009:                        len = (int) strlen(df[i].used);
                   1010:                        if (len > usedlen)
                   1011:                                usedlen = len;
                   1012:                        if (print_human)
                   1013:                                fmtret = fmt_scaled(units * (size - used),
                   1014:                                    df[i].avail);
                   1015:                        if (!print_human || fmtret == -1)
                   1016:                                snprintf(df[i].avail, sizeof(df[i].avail),
                   1017:                                    "%lld", (units * (size - used)) / 1024);
                   1018:                        len = (int) strlen(df[i].avail);
1.23      martijn  1019:                        if (len > availlen)
1.19      martijn  1020:                                availlen = len;
                   1021:                        if (size == 0)
                   1022:                                strlcpy(df[i].proc, "0%", sizeof(df[i].proc));
                   1023:                        else {
                   1024:                                snprintf(df[i].proc, sizeof(df[i].proc),
                   1025:                                    "%lld%%", (used * 100) / size);
                   1026:                        }
                   1027:                        len = (int) strlen(df[i].proc);
                   1028:                        if (len > proclen)
                   1029:                                proclen = len;
                   1030:                        j++;
                   1031:                }
                   1032:                if (j == 0) {
                   1033:                        warnx("Failed to retrieve information for %s",
                   1034:                            df[i].descr);
                   1035:                        memmove(df + i, df + i + 1,
                   1036:                            (rows - i - 1) * sizeof(*df));
                   1037:                        rows--;
                   1038:                        i--;
                   1039:                }
                   1040:        }
                   1041:
                   1042:        printf("%-*s%*s%*s%*s%*s\n",
                   1043:            descrlen, "Description",
                   1044:            NEXTTAB(descrlen) + sizelen, "Size",
                   1045:            NEXTTAB(sizelen) + usedlen, "Used",
                   1046:            NEXTTAB(usedlen) + availlen, "Available",
                   1047:            NEXTTAB(availlen) + proclen, "Used%");
                   1048:        for (i = 0; i < rows; i++) {
1.29      martijn  1049:                printf("%s%*s%*s%*s%*s%*s\n",
                   1050:                    df[i].descr, descrlen - df[i].descrwidth, "",
1.19      martijn  1051:                    NEXTTAB(descrlen) + sizelen, df[i].size,
                   1052:                    NEXTTAB(sizelen) + usedlen, df[i].used,
                   1053:                    NEXTTAB(usedlen) + availlen, df[i].avail,
                   1054:                    NEXTTAB(availlen) + proclen, df[i].proc);
                   1055:        }
1.1       martijn  1056:
                   1057:        return 0;
                   1058: }
                   1059:
                   1060: int
                   1061: snmpc_mibtree(int argc, char *argv[])
                   1062: {
                   1063:        struct oid *oid;
1.30      martijn  1064:        struct ber_oid soid;
1.1       martijn  1065:        char buf[BUFSIZ];
1.30      martijn  1066:        int i;
1.1       martijn  1067:
1.30      martijn  1068:        if (argc == 0) {
                   1069:                for (oid = NULL; (oid = smi_foreach(oid)) != NULL;) {
                   1070:                        smi_oid2string(&oid->o_id, buf, sizeof(buf),
                   1071:                            oid_lookup);
                   1072:                        printf("%s\n", buf);
                   1073:                }
                   1074:        } else {
                   1075:                for (i = 0; i < argc; i++) {
                   1076:                        if (smi_string2oid(argv[i], &soid) == -1) {
                   1077:                                warnx("%s: Unknown object identifier", argv[i]);
                   1078:                                continue;
                   1079:                        }
                   1080:                        smi_oid2string(&soid, buf, sizeof(buf), oid_lookup);
                   1081:                        printf("%s\n", buf);
                   1082:                }
1.1       martijn  1083:        }
                   1084:        return 0;
1.8       martijn  1085: }
                   1086:
                   1087: struct snmp_agent *
                   1088: snmpc_connect(char *host, char *port)
                   1089: {
                   1090:        switch (version) {
                   1091:        case SNMP_V1:
                   1092:        case SNMP_V2C:
                   1093:                return snmp_connect_v12(snmpc_parseagent(host, port), version,
                   1094:                    community);
1.9       martijn  1095:        case SNMP_V3:
                   1096:                return snmp_connect_v3(snmpc_parseagent(host, port), v3);
1.8       martijn  1097:        }
                   1098:        return NULL;
1.1       martijn  1099: }
                   1100:
                   1101: int
                   1102: snmpc_print(struct ber_element *elm)
                   1103: {
                   1104:        struct ber_oid oid;
                   1105:        char oids[SNMP_MAX_OID_STRLEN];
                   1106:        char *value;
                   1107:
                   1108:        elm = elm->be_sub;
1.16      tb       1109:        if (ober_get_oid(elm, &oid) != 0) {
1.1       martijn  1110:                errno = EINVAL;
                   1111:                return 0;
                   1112:        }
                   1113:
                   1114:        elm = elm->be_next;
1.28      martijn  1115:        value = smi_print_element(&oid, elm, smi_print_hint, output_string,
                   1116:            oid_lookup, utf8);
1.1       martijn  1117:        if (value == NULL)
                   1118:                return 0;
                   1119:
                   1120:        if (print_varbind_only)
                   1121:                printf("%s\n", value);
                   1122:        else if (print_equals) {
                   1123:                smi_oid2string(&oid, oids, sizeof(oids), oid_lookup);
                   1124:                printf("%s = %s\n", oids, value);
                   1125:        } else {
                   1126:                smi_oid2string(&oid, oids, sizeof(oids), oid_lookup);
                   1127:                printf("%s %s\n", oids, value);
                   1128:        }
                   1129:        free(value);
1.2       deraadt  1130:
1.1       martijn  1131:        return 1;
                   1132: }
                   1133:
                   1134: __dead void
1.15      martijn  1135: snmpc_printerror(enum snmp_error error, struct ber_element *varbind,
                   1136:     int index, const char *hint)
1.1       martijn  1137: {
1.15      martijn  1138:        struct ber_oid hoid, vboid;
                   1139:        char oids[SNMP_MAX_OID_STRLEN];
                   1140:        const char *oid = NULL;
                   1141:        int i;
                   1142:
                   1143:        if (index >= 1) {
                   1144:                /* Only print if the index is in the reply */
1.26      martijn  1145:                for (i = 1; varbind != NULL && i < index;
1.15      martijn  1146:                    varbind = varbind->be_next)
                   1147:                        i++;
                   1148:                if (varbind != NULL &&
1.16      tb       1149:                    ober_get_oid(varbind->be_sub, &vboid) == 0) {
1.15      martijn  1150:                        /* If user and reply conform print user input */
                   1151:                        if (hint != NULL &&
                   1152:                            smi_string2oid(hint, &hoid) == 0 &&
1.16      tb       1153:                            ober_oid_cmp(&hoid, &vboid) == 0)
1.15      martijn  1154:                                oid = hint;
                   1155:                        else
                   1156:                                oid = smi_oid2string(&vboid, oids,
                   1157:                                    sizeof(oids), oid_lookup);
                   1158:                }
                   1159:        }
                   1160:        if (oid == NULL)
                   1161:                oid = "?";
                   1162:
1.2       deraadt  1163:        switch (error) {
1.1       martijn  1164:        case SNMP_ERROR_NONE:
                   1165:                errx(1, "No error, how did I get here?");
                   1166:        case SNMP_ERROR_TOOBIG:
                   1167:                errx(1, "Can't parse oid %s: Response too big", oid);
                   1168:        case SNMP_ERROR_NOSUCHNAME:
                   1169:                errx(1, "Can't parse oid %s: No such object", oid);
                   1170:        case SNMP_ERROR_BADVALUE:
                   1171:                errx(1, "Can't parse oid %s: Bad value", oid);
                   1172:        case SNMP_ERROR_READONLY:
                   1173:                errx(1, "Can't parse oid %s: Read only", oid);
                   1174:        case SNMP_ERROR_GENERR:
                   1175:                errx(1, "Can't parse oid %s: Generic error", oid);
                   1176:        case SNMP_ERROR_NOACCESS:
                   1177:                errx(1, "Can't parse oid %s: Access denied", oid);
                   1178:        case SNMP_ERROR_WRONGTYPE:
                   1179:                errx(1, "Can't parse oid %s: Wrong type", oid);
                   1180:        case SNMP_ERROR_WRONGLENGTH:
                   1181:                errx(1, "Can't parse oid %s: Wrong length", oid);
                   1182:        case SNMP_ERROR_WRONGENC:
                   1183:                errx(1, "Can't parse oid %s: Wrong encoding", oid);
                   1184:        case SNMP_ERROR_WRONGVALUE:
                   1185:                errx(1, "Can't parse oid %s: Wrong value", oid);
                   1186:        case SNMP_ERROR_NOCREATION:
                   1187:                errx(1, "Can't parse oid %s: Can't be created", oid);
                   1188:        case SNMP_ERROR_INCONVALUE:
                   1189:                errx(1, "Can't parse oid %s: Inconsistent value", oid);
                   1190:        case SNMP_ERROR_RESUNAVAIL:
                   1191:                errx(1, "Can't parse oid %s: Resource unavailable", oid);
                   1192:        case SNMP_ERROR_COMMITFAILED:
                   1193:                errx(1, "Can't parse oid %s: Commit failed", oid);
                   1194:        case SNMP_ERROR_UNDOFAILED:
                   1195:                errx(1, "Can't parse oid %s: Undo faild", oid);
                   1196:        case SNMP_ERROR_AUTHERROR:
                   1197:                errx(1, "Can't parse oid %s: Authorization error", oid);
                   1198:        case SNMP_ERROR_NOTWRITABLE:
                   1199:                errx(1, "Can't parse oid %s: Not writable", oid);
                   1200:        case SNMP_ERROR_INCONNAME:
                   1201:                errx(1, "Can't parse oid %s: Inconsistent name", oid);
                   1202:        }
                   1203:        errx(1, "Can't parse oid %s: Unknown error (%d)", oid, error);
                   1204: }
                   1205:
                   1206: int
                   1207: snmpc_parseagent(char *agent, char *defaultport)
                   1208: {
                   1209:        struct addrinfo hints, *ai, *ai0 = NULL;
                   1210:        struct sockaddr_un saddr;
                   1211:        char *agentdup, *specifier, *hostname, *port = NULL;
                   1212:        int error;
                   1213:        int s;
                   1214:
                   1215:        if ((agentdup = specifier = strdup(agent)) == NULL)
                   1216:                err(1, NULL);
                   1217:
                   1218:        bzero(&hints, sizeof(hints));
                   1219:        if ((hostname = strchr(specifier, ':')) != NULL) {
                   1220:                *hostname++ = '\0';
                   1221:                if (strcasecmp(specifier, "udp") == 0) {
                   1222:                        hints.ai_family = AF_INET;
                   1223:                        hints.ai_socktype = SOCK_DGRAM;
                   1224:                } else if (strcasecmp(specifier, "tcp") == 0) {
                   1225:                        hints.ai_family = AF_INET;
                   1226:                        hints.ai_socktype = SOCK_STREAM;
                   1227:                } else if (strcasecmp(specifier, "udp6") == 0 ||
                   1228:                    strcasecmp(specifier, "udpv6") == 0 ||
                   1229:                    strcasecmp(specifier, "udpipv6") == 0) {
                   1230:                        hints.ai_family = AF_INET6;
                   1231:                        hints.ai_socktype = SOCK_DGRAM;
                   1232:                } else if (strcasecmp(specifier, "tcp6") == 0 ||
                   1233:                    strcasecmp(specifier, "tcpv6") == 0 ||
                   1234:                    strcasecmp(specifier, "tcpipv6") == 0) {
                   1235:                        hints.ai_family = AF_INET6;
                   1236:                        hints.ai_socktype = SOCK_STREAM;
                   1237:                } else if (strcasecmp(specifier, "unix") == 0) {
                   1238:                        hints.ai_family = AF_UNIX;
                   1239:                        hints.ai_addr = (struct sockaddr *)&saddr;
                   1240:                        hints.ai_addrlen = sizeof(saddr);
                   1241:                        saddr.sun_len = sizeof(saddr);
                   1242:                        saddr.sun_family = AF_UNIX;
                   1243:                        if (strlcpy(saddr.sun_path, hostname,
                   1244:                            sizeof(saddr.sun_path)) > sizeof(saddr.sun_path))
                   1245:                                errx(1, "Hostname path too long");
                   1246:                        ai = &hints;
                   1247:                } else {
1.22      martijn  1248:                        *--hostname = ':';
1.1       martijn  1249:                        hostname = specifier;
                   1250:                }
                   1251:        } else {
                   1252:                hostname = specifier;
1.22      martijn  1253:        }
                   1254:
                   1255:        if (hints.ai_family == AF_INET) {
                   1256:                if ((port = strchr(hostname, ':')) != NULL)
                   1257:                        *port++ = '\0';
                   1258:        } else if (hints.ai_family == AF_INET6 || hints.ai_family == 0) {
                   1259:                if (hostname[0] == '[') {
                   1260:                        hints.ai_family = AF_INET6;
                   1261:                        hostname++;
                   1262:                        if ((port = strchr(hostname, ']')) == NULL)
                   1263:                                errx(1, "invalid agent");
                   1264:                        *port++ = '\0';
                   1265:                        if (port[0] == ':')
                   1266:                                *port++ = '\0';
                   1267:                        else if (port[0] == '\0')
                   1268:                                port = NULL;
                   1269:                        else
                   1270:                                errx(1, "invalid agent");
                   1271:                } else {
                   1272:                        if ((port = strrchr(hostname, ':')) != NULL)
                   1273:                                *port++ = '\0';
                   1274:                }
1.1       martijn  1275:        }
                   1276:
                   1277:        if (hints.ai_family != AF_UNIX) {
1.22      martijn  1278:                if (hints.ai_socktype == 0)
                   1279:                        hints.ai_socktype = SOCK_DGRAM;
1.1       martijn  1280:                if (port == NULL)
                   1281:                        port = defaultport;
                   1282:                error = getaddrinfo(hostname, port, &hints, &ai0);
1.22      martijn  1283:                if (error) {
1.27      martijn  1284:                        if (error != EAI_NODATA || port == defaultport)
1.22      martijn  1285:                                errx(1, "%s", gai_strerror(error));
                   1286:                        *--port = ':';
                   1287:                        error = getaddrinfo(hostname, defaultport, &hints,
                   1288:                            &ai0);
                   1289:                        if (error)
                   1290:                                errx(1, "%s", gai_strerror(error));
                   1291:                }
1.1       martijn  1292:                s = -1;
                   1293:                for (ai = ai0; ai != NULL; ai = ai->ai_next) {
                   1294:                        if ((s = socket(ai->ai_family, ai->ai_socktype,
1.22      martijn  1295:                            ai->ai_protocol)) != -1 &&
                   1296:                            connect(s, (struct sockaddr *)ai->ai_addr,
                   1297:                            ai->ai_addrlen) != -1)
                   1298:                                break;
1.27      martijn  1299:                        close(s);
                   1300:                        s = -1;
1.1       martijn  1301:                }
1.22      martijn  1302:        } else {
                   1303:                s = socket(AF_UNIX, SOCK_STREAM, 0);
                   1304:                if (connect(s, (struct sockaddr *)ai->ai_addr,
                   1305:                    ai->ai_addrlen) == -1)
                   1306:                        err(1, "Can't connect to %s", agent);
                   1307:        }
1.1       martijn  1308:        if (s == -1)
1.22      martijn  1309:                err(1, "Can't connect to agent %s", agent);
1.1       martijn  1310:
                   1311:
                   1312:        if (ai0 != NULL)
                   1313:                freeaddrinfo(ai0);
                   1314:        free(agentdup);
                   1315:        return s;
                   1316: }
                   1317:
1.9       martijn  1318: char *
                   1319: snmpc_hex2bin(char *hexstr, size_t *binlen)
                   1320: {
                   1321:        char *decstr;
                   1322:
                   1323:        if (hexstr[0] == '0' && hexstr[1] == 'x')
                   1324:                hexstr += 2;
                   1325:        while (hexstr[0] == ' ' || hexstr[0] == '\t')
                   1326:                hexstr++;
                   1327:
                   1328:        if ((decstr = malloc((strlen(hexstr) / 2) + 1)) == NULL)
                   1329:                return NULL;
                   1330:
                   1331:        for (*binlen = 0; hexstr[0] != '\0'; (*binlen)++) {
                   1332:                hexstr[0] = toupper(hexstr[0]);
                   1333:                hexstr[1] = toupper(hexstr[1]);
                   1334:                if (hexstr[0] >= '0' && hexstr[0] <= '9')
                   1335:                        decstr[*binlen] = (hexstr[0] - '0') << 4;
                   1336:                else if (hexstr[0] >= 'A' && hexstr[0] <= 'F')
                   1337:                        decstr[*binlen] = ((hexstr[0] - 'A') + 10) << 4;
                   1338:                else
                   1339:                        goto fail;
                   1340:                if (hexstr[1] >= '0' && hexstr[1] <= '9')
                   1341:                        decstr[*binlen] |= (hexstr[1] - '0');
                   1342:                else if (hexstr[1] >= 'A' && hexstr[1] <= 'F')
                   1343:                        decstr[*binlen] |= (hexstr[1] - 'A') + 10;
                   1344:                else
                   1345:                        goto fail;
                   1346:
                   1347:                hexstr += 2;
                   1348:                while (hexstr[0] == ' ' || hexstr[0] == '\t')
                   1349:                        hexstr++;
                   1350:        }
                   1351:
                   1352:        return decstr;
                   1353: fail:
                   1354:        errno = EINVAL;
                   1355:        free(decstr);
                   1356:        return NULL;
1.29      martijn  1357: }
                   1358:
                   1359: ssize_t
                   1360: snmpc_mbswidth(char *str)
                   1361: {
                   1362:        wchar_t wc;
                   1363:        size_t width = 0;
                   1364:        size_t i;
                   1365:        int len;
                   1366:
                   1367:        for (i = 0; (len = mbtowc(&wc, &(str[i]), MB_CUR_MAX)) != 0; i += len) {
                   1368:                if (len == -1) {
                   1369:                        mbtowc(NULL, NULL, MB_CUR_MAX);
                   1370:                        return -1;
                   1371:                }
                   1372:                width += wcwidth(wc);
                   1373:        }
                   1374:        return width;
1.13      martijn  1375: }
                   1376:
                   1377: struct ber_element *
                   1378: snmpc_varbindparse(int argc, char *argv[])
                   1379: {
                   1380:        struct ber_oid oid, oidval;
                   1381:        struct in_addr addr4;
                   1382:        char *addr = (char *)&addr4;
                   1383:        char *str = NULL, *tmpstr, *endstr;
                   1384:        const char *errstr = NULL;
                   1385:        struct ber_element *varbind = NULL, *vblist = NULL;
                   1386:        int i, ret;
                   1387:        size_t strl, byte;
                   1388:        long long lval;
                   1389:
                   1390:        if (argc % 3 != 0)
                   1391:                usage();
                   1392:        for (i = 0; i < argc; i += 3) {
                   1393:                if (smi_string2oid(argv[i], &oid) == -1)
                   1394:                        errx(1, "Invalid oid: %s\n", argv[i]);
                   1395:                switch (argv[i + 1][0]) {
                   1396:                case 'a':
                   1397:                        ret = inet_pton(AF_INET, argv[i + 2], &addr4);
                   1398:                        if (ret == -1)
                   1399:                                err(1, "inet_pton");
                   1400:                        if (ret == 0)
                   1401:                                errx(1, "%s: Bad value notation (%s)", argv[i],
                   1402:                                    argv[i + 2]);
1.16      tb       1403:                        if ((varbind = ober_printf_elements(varbind, "{Oxt}",
1.13      martijn  1404:                            &oid, addr, sizeof(addr4), BER_CLASS_APPLICATION,
                   1405:                            SNMP_T_IPADDR)) == NULL)
1.16      tb       1406:                                err(1, "ober_printf_elements");
1.13      martijn  1407:                        break;
                   1408:                case 'b':
                   1409:                        tmpstr = argv[i + 2];
                   1410:                        strl = 0;
                   1411:                        do {
                   1412:                                lval = strtoll(tmpstr, &endstr, 10);
                   1413:                                if (endstr[0] != ' ' && endstr[0] != '\t' &&
                   1414:                                    endstr[0] != ',' && endstr[0] != '\0')
                   1415:                                        errx(1, "%s: Bad value notation (%s)",
                   1416:                                            argv[i], argv[i + 2]);
                   1417:                                if (tmpstr == endstr) {
                   1418:                                        tmpstr++;
                   1419:                                        continue;
                   1420:                                }
                   1421:                                if (lval < 0)
                   1422:                                        errx(1, "%s: Bad value notation (%s)",
                   1423:                                            argv[i], argv[i + 2]);
                   1424:                                byte = lval / 8;
                   1425:                                if (byte >= strl) {
                   1426:                                        if ((str = recallocarray(str, strl,
                   1427:                                            byte + 1, 1)) == NULL)
                   1428:                                                err(1, "malloc");
                   1429:                                        strl = byte + 1;
                   1430:                                }
                   1431:                                str[byte] |= 0x80 >> (lval % 8);
                   1432:                                tmpstr = endstr + 1;
                   1433:                        } while (endstr[0] != '\0');
                   1434:                        /*
                   1435:                         * RFC3416 Section 2.5
                   1436:                         * A BITS value is encoded as an OCTET STRING
                   1437:                         */
                   1438:                        goto pastestring;
                   1439:                case 'c':
                   1440:                        lval = strtonum(argv[i + 2], INT32_MIN, INT32_MAX,
                   1441:                            &errstr);
                   1442:                        if (errstr != NULL)
                   1443:                                errx(1, "%s: Bad value notation (%s)", argv[i],
                   1444:                                    argv[i + 2]);
1.16      tb       1445:                        if ((varbind = ober_printf_elements(varbind, "{Oit}",
1.13      martijn  1446:                            &oid, lval, BER_CLASS_APPLICATION,
                   1447:                            SNMP_T_COUNTER32)) == NULL)
1.16      tb       1448:                                err(1, "ober_printf_elements");
1.13      martijn  1449:                        break;
                   1450:                case 'd':
                   1451:                        /* String always shrinks */
                   1452:                        if ((str = malloc(strlen(argv[i + 2]))) == NULL)
                   1453:                                err(1, "malloc");
                   1454:                        tmpstr = argv[i + 2];
                   1455:                        strl = 0;
                   1456:                        do {
                   1457:                                lval = strtoll(tmpstr, &endstr, 10);
                   1458:                                if (endstr[0] != ' ' && endstr[0] != '\t' &&
                   1459:                                    endstr[0] != '\0')
                   1460:                                        errx(1, "%s: Bad value notation (%s)",
                   1461:                                            argv[i], argv[i + 2]);
                   1462:                                if (tmpstr == endstr) {
                   1463:                                        tmpstr++;
                   1464:                                        continue;
                   1465:                                }
                   1466:                                if (lval < 0 || lval > 0xff)
                   1467:                                        errx(1, "%s: Bad value notation (%s)",
                   1468:                                            argv[i], argv[i + 2]);
                   1469:                                str[strl++] = (unsigned char) lval;
                   1470:                                tmpstr = endstr + 1;
                   1471:                        } while (endstr[0] != '\0');
                   1472:                        goto pastestring;
                   1473:                case 'u':
                   1474:                case 'i':
                   1475:                        lval = strtonum(argv[i + 2], LLONG_MIN, LLONG_MAX,
                   1476:                            &errstr);
                   1477:                        if (errstr != NULL)
                   1478:                                errx(1, "%s: Bad value notation (%s)", argv[i],
                   1479:                                    argv[i + 2]);
1.16      tb       1480:                        if ((varbind = ober_printf_elements(varbind, "{Oi}",
1.13      martijn  1481:                            &oid, lval)) == NULL)
1.16      tb       1482:                                err(1, "ober_printf_elements");
1.13      martijn  1483:                        break;
                   1484:                case 'n':
1.16      tb       1485:                        if ((varbind = ober_printf_elements(varbind, "{O0}",
1.13      martijn  1486:                            &oid)) == NULL)
1.16      tb       1487:                                err(1, "ober_printf_elements");
1.13      martijn  1488:                        break;
                   1489:                case 'o':
                   1490:                        if (smi_string2oid(argv[i + 2], &oidval) == -1)
                   1491:                                errx(1, "%s: Unknown Object Identifier (Sub-id "
                   1492:                                    "not found: (top) -> %s)", argv[i],
                   1493:                                    argv[i + 2]);
1.16      tb       1494:                        if ((varbind = ober_printf_elements(varbind, "{OO}",
1.13      martijn  1495:                            &oid, &oidval)) == NULL)
1.16      tb       1496:                                err(1, "ober_printf_elements");
1.13      martijn  1497:                        break;
                   1498:                case 's':
                   1499:                        if ((str = strdup(argv[i + 2])) == NULL)
                   1500:                                err(1, NULL);
                   1501:                        strl = strlen(argv[i + 2]);
                   1502: pastestring:
1.16      tb       1503:                        if ((varbind = ober_printf_elements(varbind, "{Ox}",
1.13      martijn  1504:                            &oid, str, strl)) == NULL)
1.16      tb       1505:                                err(1, "ober_printf_elements");
1.13      martijn  1506:                        free(str);
                   1507:                        break;
                   1508:                case 't':
                   1509:                        lval = strtonum(argv[i + 2], LLONG_MIN, LLONG_MAX,
                   1510:                            &errstr);
                   1511:                        if (errstr != NULL)
                   1512:                                errx(1, "%s: Bad value notation (%s)", argv[i],
                   1513:                                    argv[i + 2]);
1.16      tb       1514:                        if ((varbind = ober_printf_elements(varbind, "{Oit}",
1.13      martijn  1515:                            &oid, lval, BER_CLASS_APPLICATION,
                   1516:                            SNMP_T_TIMETICKS)) == NULL)
1.16      tb       1517:                                err(1, "ober_printf_elements");
1.13      martijn  1518:                        break;
                   1519:                case 'x':
                   1520:                        /* String always shrinks */
                   1521:                        if ((str = malloc(strlen(argv[i + 2]))) == NULL)
                   1522:                                err(1, "malloc");
                   1523:                        tmpstr = argv[i + 2];
                   1524:                        strl = 0;
                   1525:                        do {
                   1526:                                lval = strtoll(tmpstr, &endstr, 16);
                   1527:                                if (endstr[0] != ' ' && endstr[0] != '\t' &&
                   1528:                                    endstr[0] != '\0')
                   1529:                                        errx(1, "%s: Bad value notation (%s)",
                   1530:                                            argv[i], argv[i + 2]);
                   1531:                                if (tmpstr == endstr) {
                   1532:                                        tmpstr++;
                   1533:                                        continue;
                   1534:                                }
                   1535:                                if (lval < 0 || lval > 0xff)
                   1536:                                        errx(1, "%s: Bad value notation (%s)",
                   1537:                                            argv[i], argv[i + 2]);
                   1538:                                str[strl++] = (unsigned char) lval;
                   1539:                                tmpstr = endstr + 1;
                   1540:                        } while (endstr[0] != '\0');
                   1541:                        goto pastestring;
                   1542:                default:
                   1543:                        usage();
                   1544:                }
                   1545:                if (vblist == NULL)
                   1546:                        vblist = varbind;
                   1547:        }
                   1548:
                   1549:        return vblist;
1.9       martijn  1550: }
                   1551:
1.1       martijn  1552: __dead void
                   1553: usage(void)
                   1554: {
                   1555:        size_t i;
                   1556:
                   1557:        if (snmp_app != NULL) {
1.9       martijn  1558:                fprintf(stderr, "usage: snmp %s%s%s\n",
1.4       martijn  1559:                    snmp_app->name,
1.1       martijn  1560:                    snmp_app->usecommonopt ?
1.10      martijn  1561:                    " [-A authpass] [-a digest] [-c community] [-e secengineid]\n"
1.11      martijn  1562:                    "            [-E ctxengineid] [-K localpriv] [-k localauth] [-l seclevel]\n"
                   1563:                    "            [-n ctxname] [-O afnqvxSQ] [-r retries] [-t timeout] [-u user]\n"
                   1564:                    "            [-v version] [-X privpass] [-x cipher] [-Z boots,time]\n"
1.9       martijn  1565:                    "            " : "",
1.1       martijn  1566:                    snmp_app->usage == NULL ? "" : snmp_app->usage);
                   1567:                exit(1);
                   1568:        }
                   1569:        for (i = 0; i < (sizeof(snmp_apps)/sizeof(*snmp_apps)); i++) {
1.4       martijn  1570:                if (i == 0)
                   1571:                        fprintf(stderr, "usage: ");
                   1572:                else
                   1573:                        fprintf(stderr, "       ");
                   1574:                fprintf(stderr, "snmp %s%s %s\n",
                   1575:                    snmp_apps[i].name,
1.1       martijn  1576:                    snmp_apps[i].usecommonopt ?
1.17      martijn  1577:                    " [options]" : "",
1.4       martijn  1578:                    snmp_apps[i].usage ? snmp_apps[i].usage : "");
1.1       martijn  1579:        }
                   1580:        exit(1);
                   1581: }