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

1.13    ! martijn     1: /*     $OpenBSD: snmpc.c,v 1.12 2019/10/03 07:23:46 semarie 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>
                     32: #include <netdb.h>
                     33: #include <poll.h>
                     34: #include <stdio.h>
                     35: #include <stdlib.h>
                     36: #include <stdint.h>
                     37: #include <string.h>
                     38: #include <time.h>
                     39: #include <unistd.h>
                     40:
                     41: #include "smi.h"
                     42: #include "snmp.h"
1.9       martijn    43: #include "usm.h"
1.1       martijn    44:
1.11      martijn    45: #define GETOPT_COMMON          "A:a:c:E:e:K:k:l:n:O:r:t:u:v:X:x:Z:"
1.1       martijn    46:
                     47: int snmpc_get(int, char *[]);
                     48: int snmpc_walk(int, char *[]);
1.13    ! martijn    49: int snmpc_set(int, char *[]);
1.1       martijn    50: int snmpc_trap(int, char *[]);
                     51: int snmpc_mibtree(int, char *[]);
1.8       martijn    52: struct snmp_agent *snmpc_connect(char *, char *);
1.1       martijn    53: int snmpc_parseagent(char *, char *);
                     54: int snmpc_print(struct ber_element *);
                     55: __dead void snmpc_printerror(enum snmp_error, char *);
1.9       martijn    56: char *snmpc_hex2bin(char *, size_t *);
1.13    ! martijn    57: struct ber_element *snmpc_varbindparse(int, char *[]);
1.1       martijn    58: void usage(void);
                     59:
                     60: struct snmp_app {
                     61:        const char *name;
                     62:        const int usecommonopt;
                     63:        const char *optstring;
                     64:        const char *usage;
1.2       deraadt    65:        int (*exec)(int, char *[]);
1.1       martijn    66: };
                     67:
                     68: struct snmp_app snmp_apps[] = {
1.2       deraadt    69:        { "get", 1, NULL, "agent oid ...", snmpc_get },
                     70:        { "getnext", 1, NULL, "agent oid ...", snmpc_get },
1.7       deraadt    71:        { "walk", 1, "C:", "[-C cIipt] [-C E endoid] agent [oid]", snmpc_walk },
1.2       deraadt    72:        { "bulkget", 1, "C:", "[-C n<nonrep>r<maxrep>] agent oid ...", snmpc_get },
                     73:        { "bulkwalk", 1, "C:", "[-C cipn<nonrep>r<maxrep>] agent [oid]", snmpc_walk },
1.13    ! martijn    74:        { "set", 1, NULL, "agent oid type value [oid type value] ...", snmpc_set },
1.2       deraadt    75:        { "trap", 1, NULL, "agent uptime oid [oid type value] ...", snmpc_trap },
                     76:        { "mibtree", 0, "O:", "[-O fnS]", snmpc_mibtree }
1.1       martijn    77: };
                     78: struct snmp_app *snmp_app = NULL;
                     79:
                     80: char *community = "public";
1.9       martijn    81: struct snmp_v3 *v3;
1.1       martijn    82: char *mib = "mib_2";
                     83: int retries = 5;
                     84: int timeout = 1;
1.9       martijn    85: enum snmp_version version = SNMP_V2C;
1.1       martijn    86: int print_equals = 1;
                     87: int print_varbind_only = 0;
                     88: int print_summary = 0;
                     89: int print_time = 0;
                     90: int walk_check_increase = 1;
                     91: int walk_fallback_oid = 1;
                     92: int walk_include_oid = 0;
                     93: int smi_print_hint = 1;
                     94: int non_repeaters = 0;
                     95: int max_repetitions = 10;
                     96: struct ber_oid walk_end = {{0}, 0};
                     97: enum smi_oid_lookup oid_lookup = smi_oidl_short;
                     98: enum smi_output_string output_string = smi_os_default;
                     99:
                    100: int
                    101: main(int argc, char *argv[])
                    102: {
1.10      martijn   103:        const EVP_MD *md = NULL;
1.11      martijn   104:        const EVP_CIPHER *cipher = NULL;
1.9       martijn   105:        struct snmp_sec *sec;
                    106:        char *user = NULL;
1.10      martijn   107:        enum usm_key_level authkeylevel;
                    108:        char *authkey = NULL;
                    109:        size_t authkeylen = 0;
1.11      martijn   110:        enum usm_key_level privkeylevel;
                    111:        char *privkey = NULL;
                    112:        size_t privkeylen = 0;
1.9       martijn   113:        int seclevel = SNMP_MSGFLAG_REPORT;
                    114:        char *ctxname = NULL;
                    115:        char *ctxengineid = NULL, *secengineid = NULL;
                    116:        size_t ctxengineidlen, secengineidlen;
                    117:        int zflag = 0;
                    118:        long long boots, time;
1.1       martijn   119:        char optstr[BUFSIZ];
                    120:        const char *errstr;
                    121:        char *strtolp;
                    122:        int ch;
                    123:        size_t i;
                    124:
                    125:        if (pledge("stdio inet dns", NULL) == -1)
                    126:                err(1, "pledge");
1.2       deraadt   127:
1.1       martijn   128:        if (argc <= 1)
                    129:                usage();
                    130:
                    131:        for (i = 0; i < sizeof(snmp_apps)/sizeof(*snmp_apps); i++) {
                    132:                if (strcmp(snmp_apps[i].name, argv[1]) == 0) {
                    133:                        snmp_app = &snmp_apps[i];
                    134:                        if (snmp_app->optstring != NULL) {
                    135:                                if (strlcpy(optstr, snmp_app->optstring,
                    136:                                    sizeof(optstr)) > sizeof(optstr))
                    137:                                        errx(1, "strlcat");
                    138:                        }
                    139:                        break;
                    140:                }
                    141:        }
                    142:        if (snmp_app == NULL)
                    143:                usage();
                    144:
                    145:        if (snmp_app->usecommonopt) {
                    146:                if (strlcat(optstr, GETOPT_COMMON, sizeof(optstr)) >
                    147:                    sizeof(optstr))
                    148:                        errx(1, "strlcpy");
                    149:        }
                    150:
                    151:        argc--;
                    152:        argv++;
                    153:
                    154:        smi_init();
                    155:
                    156:        while ((ch = getopt(argc, argv, optstr)) != -1) {
                    157:                switch (ch) {
1.10      martijn   158:                case 'A':
                    159:                        authkey = optarg;
                    160:                        authkeylen = strlen(authkey);
                    161:                        authkeylevel = USM_KEY_PASSWORD;
                    162:                        break;
                    163:                case 'a':
                    164:                        if (strcasecmp(optarg, "MD5") == 0)
                    165:                                md = EVP_md5();
                    166:                        else if (strcasecmp(optarg, "SHA") == 0)
                    167:                                md = EVP_sha1();
                    168:                        else if (strcasecmp(optarg, "SHA-224") == 0)
                    169:                                md = EVP_sha224();
                    170:                        else if (strcasecmp(optarg, "SHA-256") == 0)
                    171:                                md = EVP_sha256();
                    172:                        else if (strcasecmp(optarg, "SHA-384") == 0)
                    173:                                md = EVP_sha384();
                    174:                        else if (strcasecmp(optarg, "SHA-512") == 0)
                    175:                                md = EVP_sha512();
                    176:                        else
                    177:                                errx(1, "Invalid authentication protocol "
                    178:                                    "specified after -a flag: %s", optarg);
                    179:                        break;
1.1       martijn   180:                case 'c':
                    181:                        community = optarg;
                    182:                        break;
1.9       martijn   183:                case 'E':
                    184:                        ctxengineid = snmpc_hex2bin(optarg,
                    185:                            &ctxengineidlen);
                    186:                        if (ctxengineid == NULL) {
                    187:                                if (errno == EINVAL)
                    188:                                        errx(1, "Bad engine ID value "
                    189:                                            "after -3E flag.");
                    190:                                err(1, "-3E");
                    191:                        }
                    192:                        break;
                    193:                case 'e':
                    194:                        secengineid = snmpc_hex2bin(optarg,
                    195:                            &secengineidlen);
                    196:                        if (secengineid == NULL) {
                    197:                                if (errno == EINVAL)
                    198:                                        errx(1, "Bad engine ID value "
                    199:                                            "after -3e flag.");
                    200:                                err(1, "-3e");
                    201:                        }
                    202:                        break;
1.11      martijn   203:                case 'K':
                    204:                        privkey = snmpc_hex2bin(optarg, &privkeylen);
                    205:                        if (privkey == NULL) {
                    206:                                if (errno == EINVAL)
                    207:                                        errx(1, "Bad key value after "
                    208:                                            "-3K flag.");
                    209:                                errx(1, "-3K");
                    210:                        }
                    211:                        privkeylevel = USM_KEY_LOCALIZED;
                    212:                                break;
1.10      martijn   213:                case 'k':
                    214:                        authkey = snmpc_hex2bin(optarg, &authkeylen);
                    215:                        if (authkey == NULL) {
                    216:                                if (errno == EINVAL)
                    217:                                        errx(1, "Bad key value after -k flag.");
                    218:                                err(1, "-k");
                    219:                        }
                    220:                        authkeylevel = USM_KEY_LOCALIZED;
                    221:                        break;
                    222:                case 'l':
                    223:                        if (strcasecmp(optarg, "noAuthNoPriv") == 0)
                    224:                                seclevel = SNMP_MSGFLAG_REPORT;
                    225:                        else if (strcasecmp(optarg, "authNoPriv") == 0)
                    226:                                seclevel = SNMP_MSGFLAG_AUTH |
                    227:                                    SNMP_MSGFLAG_REPORT;
1.11      martijn   228:                        else if (strcasecmp(optarg, "authPriv") == 0)
                    229:                                seclevel = SNMP_MSGFLAG_AUTH |
                    230:                                    SNMP_MSGFLAG_PRIV | SNMP_MSGFLAG_REPORT;
1.10      martijn   231:                        else
                    232:                                errx(1, "Invalid security level specified "
                    233:                                    "after -l flag: %s", optarg);
                    234:                        break;
1.9       martijn   235:                case 'n':
                    236:                        ctxname = optarg;
                    237:                        break;
1.1       martijn   238:                case 'r':
                    239:                        if ((retries = strtonum(optarg, 0, INT_MAX,
                    240:                            &errstr)) == 0) {
                    241:                                if (errstr != NULL)
                    242:                                        errx(1, "-r: %s argument", errstr);
                    243:                        }
                    244:                        break;
                    245:                case 't':
                    246:                        if ((timeout = strtonum(optarg, 1, INT_MAX,
                    247:                            &errstr)) == 0) {
                    248:                                if (errstr != NULL)
                    249:                                        errx(1, "-t: %s argument", errstr);
                    250:                        }
                    251:                        break;
1.9       martijn   252:                case 'u':
                    253:                        user = optarg;
                    254:                        break;
1.1       martijn   255:                case 'v':
                    256:                        if (strcmp(optarg, "1") == 0)
                    257:                                version = SNMP_V1;
                    258:                        else if (strcmp(optarg, "2c") == 0)
                    259:                                version = SNMP_V2C;
1.9       martijn   260:                        else if (strcmp(optarg, "3") == 0)
                    261:                                version = SNMP_V3;
1.1       martijn   262:                        else
                    263:                                errc(1, EINVAL, "-v");
                    264:                        break;
                    265:                case 'C':
                    266:                        for (i = 0; i < strlen(optarg); i++) {
                    267:                                switch (optarg[i]) {
                    268:                                case 'c':
                    269:                                        if (strcmp(snmp_app->name, "walk") &&
                    270:                                            strcmp(snmp_app->name, "bulkwalk"))
                    271:                                                usage();
                    272:                                        walk_check_increase = 0;
                    273:                                        break;
                    274:                                case 'i':
                    275:                                        if (strcmp(snmp_app->name, "walk") &&
                    276:                                            strcmp(snmp_app->name, "bulkwalk"))
                    277:                                                usage();
                    278:                                        walk_include_oid = 1;
                    279:                                        break;
                    280:                                case 'n':
                    281:                                        if (strcmp(snmp_app->name, "bulkget") &&
                    282:                                            strcmp(snmp_app->name, "bulkwalk"))
                    283:                                                usage();
                    284:                                        errno = 0;
                    285:                                        non_repeaters = strtol(&optarg[i + 1],
                    286:                                            &strtolp, 10);
                    287:                                        if (non_repeaters < 0 ||
                    288:                                            errno == ERANGE) {
                    289:                                                if (non_repeaters < 0)
                    290:                                                        errx(1, "%s%s",
                    291:                                                            "-Cn: too small ",
                    292:                                                            "argument");
                    293:                                                else
                    294:                                                        errx(1, "%s%s",
                    295:                                                            "-Cn: too large",
                    296:                                                            "argument");
                    297:                                        } else if (&optarg[i + 1] == strtolp)
                    298:                                                errx(1, "-Cn invalid argument");
                    299:                                        i = strtolp - optarg - 1;
                    300:                                        break;
                    301:                                case 'p':
                    302:                                        if (strcmp(snmp_app->name, "walk") &&
                    303:                                            strcmp(snmp_app->name, "bulkwalk"))
                    304:                                                usage();
                    305:                                        print_summary = 1;
                    306:                                        break;
                    307:                                case 'r':
                    308:                                        if (strcmp(snmp_app->name, "bulkget") &&
                    309:                                            strcmp(snmp_app->name, "bulkwalk"))
                    310:                                                usage();
                    311:                                        errno = 0;
                    312:                                        max_repetitions = strtol(&optarg[i + 1],
                    313:                                            &strtolp, 10);
                    314:                                        if (max_repetitions < 0 ||
                    315:                                            errno == ERANGE) {
                    316:                                                if (max_repetitions < 0)
                    317:                                                        errx(1, "%s%s",
                    318:                                                            "-Cr: too small ",
                    319:                                                            "argument");
                    320:                                                else
                    321:                                                        errx(1, "%s%s",
                    322:                                                            "-Cr: too large",
                    323:                                                            "argument");
                    324:                                        } else if (&optarg[i + 1] == strtolp)
                    325:                                                errx(1, "-Cr invalid argument");
                    326:                                        i = strtolp - optarg - 1;
                    327:                                        break;
                    328:                                case 't':
                    329:                                        if (strcmp(snmp_app->name, "walk"))
                    330:                                                usage();
                    331:                                        print_time = 1;
                    332:                                        break;
                    333:                                case 'E':
                    334:                                        if (strcmp(snmp_app->name, "walk"))
                    335:                                                usage();
                    336:                                        if (smi_string2oid(argv[optind],
                    337:                                            &walk_end) != 0)
                    338:                                                errx(1, "%s: %s",
                    339:                                                    "Unknown Object Identifier",
                    340:                                                    argv[optind]);
                    341:                                        optind++;
                    342:                                        continue;
                    343:                                case 'I':
                    344:                                        if (strcmp(snmp_app->name, "walk"))
                    345:                                                usage();
                    346:                                        walk_fallback_oid = 0;
                    347:                                        break;
                    348:                                default:
                    349:                                        usage();
                    350:                                }
                    351:                                if (optarg[i] == 'E')
                    352:                                        break;
                    353:                        }
                    354:                        break;
                    355:                case 'O':
                    356:                        for (i = 0; i < strlen(optarg); i++) {
                    357:                                if (strcmp(snmp_app->name, "mibtree") == 0 &&
                    358:                                    optarg[i] != 'f' && optarg[i] != 'n' &&
                    359:                                    optarg[i] != 'S')
                    360:                                                usage();
                    361:                                switch (optarg[i]) {
                    362:                                case 'a':
                    363:                                        output_string = smi_os_ascii;
                    364:                                        break;
                    365:                                case 'f':
                    366:                                        oid_lookup = smi_oidl_full;
                    367:                                        break;
                    368:                                case 'n':
                    369:                                        oid_lookup = smi_oidl_numeric;
                    370:                                        break;
                    371:                                case 'q':
                    372:                                        print_equals = 0;
                    373:                                        smi_print_hint = 0;
                    374:                                        break;
                    375:                                case 'v':
1.2       deraadt   376:                                        print_varbind_only = 1;
1.1       martijn   377:                                        break;
                    378:                                case 'x':
                    379:                                        output_string = smi_os_hex;
                    380:                                        break;
                    381:                                case 'S':
                    382:                                        oid_lookup = smi_oidl_short;
                    383:                                        break;
                    384:                                case 'Q':
                    385:                                        smi_print_hint = 0;
                    386:                                        break;
                    387:                                default:
                    388:                                        usage();
                    389:                                }
                    390:                        }
                    391:                        break;
1.11      martijn   392:                case 'X':
                    393:                        privkey = optarg;
                    394:                        privkeylen = strlen(privkey);
                    395:                        privkeylevel = USM_KEY_PASSWORD;
                    396:                        break;
                    397:                case 'x':
                    398:                        if (strcasecmp(optarg, "DES") == 0)
                    399:                                cipher = EVP_des_cbc();
                    400:                        else if (strcasecmp(optarg, "AES") == 0)
                    401:                                cipher = EVP_aes_128_cfb128();
                    402:                        else
                    403:                                errx(1, "Invalid privacy protocol "
                    404:                                    "specified after -3x flag: %s",
                    405:                                    optarg);
                    406:                        break;
1.9       martijn   407:                case 'Z':
                    408:                        boots = strtoll(optarg, &strtolp, 10);
                    409:                        if (boots < 0 || strtolp == optarg || strtolp[0] != ',')
                    410:                                usage();
                    411:                        strtolp++;
                    412:                        while (strtolp[0] == ' ' && strtolp[0] == '\t')
                    413:                                strtolp++;
                    414:                        time = strtoll(strtolp, &strtolp, 10);
                    415:                        if (boots < 0 || strtolp == optarg)
                    416:                                usage();
                    417:                        zflag = 1;
                    418:                        break;
1.1       martijn   419:                default:
                    420:                        usage();
                    421:                }
                    422:        }
                    423:        argc -= optind;
                    424:        argv += optind;
                    425:
1.9       martijn   426:        if (version == SNMP_V3) {
                    427:                /* Setup USM */
                    428:                if (user == NULL || user[0] == '\0')
                    429:                        errx(1, "No securityName specified");
                    430:                if ((sec = usm_init(user, strlen(user))) == NULL)
                    431:                        err(1, "usm_init");
1.10      martijn   432:                if (seclevel & SNMP_MSGFLAG_AUTH) {
                    433:                        if (md == NULL)
                    434:                                md = EVP_md5();
                    435:                        if (authkey == NULL)
                    436:                                errx(1, "No authKey or authPassword specified");
                    437:                        if (usm_setauth(sec, md, authkey, authkeylen,
                    438:                            authkeylevel) == -1)
                    439:                                err(1, "Can't set authkey");
                    440:                }
1.11      martijn   441:                if (seclevel & SNMP_MSGFLAG_PRIV) {
                    442:                        if (cipher == NULL)
                    443:                                cipher = EVP_des_cbc();
                    444:                        if (privkey == NULL)
                    445:                                errx(1, "No privKey or privPassword specified");
                    446:                        if (usm_setpriv(sec, cipher, privkey, privkeylen,
                    447:                            privkeylevel) == -1)
                    448:                                err(1, "Can't set authkey");
                    449:                }
1.9       martijn   450:                if (secengineid != NULL) {
                    451:                        if (usm_setengineid(sec, secengineid,
                    452:                            secengineidlen) == -1)
                    453:                                err(1, "Can't set secengineid");
                    454:                }
                    455:                if (zflag)
                    456:                        if (usm_setbootstime(sec, boots, time) == -1)
                    457:                                err(1, "Can't set boots/time");
                    458:                v3 = snmp_v3_init(seclevel, ctxname, ctxname == NULL ? 0 :
                    459:                    strlen(ctxname), sec);
                    460:                if (v3 == NULL)
                    461:                        err(1, "snmp_v3_init");
                    462:                if (ctxengineid != NULL) {
                    463:                        if (snmp_v3_setengineid(v3, ctxengineid,
                    464:                            ctxengineidlen) == -1)
                    465:                                err(1, "Can't set ctxengineid");
                    466:                }
                    467:        }
                    468:
                    469:
1.1       martijn   470:        return snmp_app->exec(argc, argv);
                    471: }
                    472:
                    473: int
                    474: snmpc_get(int argc, char *argv[])
                    475: {
                    476:        struct ber_oid *oid;
                    477:        struct ber_element *pdu, *varbind;
                    478:        struct snmp_agent *agent;
                    479:        int errorstatus, errorindex;
                    480:        int i;
1.9       martijn   481:        int class;
                    482:        unsigned type;
1.1       martijn   483:
                    484:        if (argc < 2)
                    485:                usage();
                    486:
1.8       martijn   487:        if ((agent = snmpc_connect(argv[0], "161")) == NULL)
1.1       martijn   488:                err(1, "%s", snmp_app->name);
                    489:        agent->timeout = timeout;
                    490:        agent->retries = retries;
                    491:
                    492:        if (pledge("stdio", NULL) == -1)
                    493:                err(1, "pledge");
                    494:        argc--;
                    495:        argv++;
                    496:
                    497:        oid = reallocarray(NULL, argc, sizeof(*oid));
1.3       deraadt   498:        if (oid == NULL)
                    499:                err(1, "malloc");
1.1       martijn   500:        for (i = 0; i < argc; i++) {
                    501:                if (smi_string2oid(argv[i], &oid[i]) == -1)
1.12      semarie   502:                        errx(1, "%s: Unknown object identifier", argv[i]);
1.1       martijn   503:        }
                    504:        if (strcmp(snmp_app->name, "getnext") == 0) {
                    505:                if ((pdu = snmp_getnext(agent, oid, argc)) == NULL)
                    506:                        err(1, "getnext");
                    507:        } else if (strcmp(snmp_app->name, "bulkget") == 0) {
                    508:                if (version < SNMP_V2C)
                    509:                        errx(1, "Cannot send V2 PDU on V1 session");
                    510:                if (non_repeaters > argc)
                    511:                        errx(1, "need more objects than -Cn<num>");
                    512:                if ((pdu = snmp_getbulk(agent, oid, argc, non_repeaters,
                    513:                    max_repetitions)) == NULL)
                    514:                        err(1, "bulkget");
                    515:        } else {
                    516:                if ((pdu = snmp_get(agent, oid, argc)) == NULL)
                    517:                        err(1, "get");
                    518:        }
                    519:
1.9       martijn   520:        (void) ber_scanf_elements(pdu, "t{Sdd{e", &class, &type, &errorstatus,
                    521:            &errorindex, &varbind);
1.1       martijn   522:        if (errorstatus != 0)
                    523:                snmpc_printerror((enum snmp_error) errorstatus,
1.6       martijn   524:                    argv[errorindex - 1]);
1.1       martijn   525:
1.9       martijn   526:        if (class == BER_CLASS_CONTEXT && type == SNMP_C_REPORT)
                    527:                printf("Received report:\n");
1.1       martijn   528:        for (; varbind != NULL; varbind = varbind->be_next) {
                    529:                if (!snmpc_print(varbind))
                    530:                        err(1, "Can't print response");
                    531:        }
                    532:        ber_free_elements(pdu);
                    533:        snmp_free_agent(agent);
                    534:        return 0;
                    535: }
                    536:
                    537: int
                    538: snmpc_walk(int argc, char *argv[])
                    539: {
                    540:        struct ber_oid oid, loid, noid;
                    541:        struct ber_element *pdu, *varbind, *value;
                    542:        struct timespec start, finish;
                    543:        struct snmp_agent *agent;
                    544:        const char *oids;
                    545:        char oidstr[SNMP_MAX_OID_STRLEN];
                    546:        int n = 0, prev_cmp;
                    547:        int errorstatus, errorindex;
1.9       martijn   548:        int class;
                    549:        unsigned type;
1.1       martijn   550:
                    551:        if (strcmp(snmp_app->name, "bulkwalk") == 0 && version < SNMP_V2C)
                    552:                errx(1, "Cannot send V2 PDU on V1 session");
                    553:        if (argc < 1 || argc > 2)
                    554:                usage();
                    555:        oids = argc == 1 ? mib : argv[1];
                    556:
1.8       martijn   557:        if ((agent = snmpc_connect(argv[0], "161"))== NULL)
1.1       martijn   558:                err(1, "%s", snmp_app->name);
                    559:        agent->timeout = timeout;
                    560:        agent->retries = retries;
                    561:        if (pledge("stdio", NULL) == -1)
                    562:                err(1, "pledge");
                    563:
                    564:        if (smi_string2oid(oids, &oid) == -1)
                    565:                errx(1, "%s: Unknown object identifier", oids);
                    566:        bcopy(&oid, &noid, sizeof(noid));
                    567:        if (print_time)
                    568:                clock_gettime(CLOCK_MONOTONIC, &start);
                    569:
                    570:        if (walk_include_oid) {
                    571:                if ((pdu = snmp_get(agent, &oid, 1)) == NULL)
                    572:                        err(1, "%s", snmp_app->name);
                    573:
1.9       martijn   574:                (void) ber_scanf_elements(pdu, "t{Sdd{e", &class, &type,
                    575:                    &errorstatus, &errorindex, &varbind);
1.1       martijn   576:                if (errorstatus != 0)
                    577:                        snmpc_printerror((enum snmp_error) errorstatus,
1.6       martijn   578:                            argv[errorindex - 1]);
1.1       martijn   579:
1.9       martijn   580:                if (class == BER_CLASS_CONTEXT && type == SNMP_C_REPORT)
                    581:                        printf("Received report:\n");
1.1       martijn   582:                if (!snmpc_print(varbind))
                    583:                        err(1, "Can't print response");
                    584:                ber_free_element(pdu);
1.9       martijn   585:                if (class == BER_CLASS_CONTEXT && type == SNMP_C_REPORT)
                    586:                        return 1;
1.1       martijn   587:                n++;
                    588:        }
                    589:        while (1) {
                    590:                bcopy(&noid, &loid, sizeof(loid));
                    591:                if (strcmp(snmp_app->name, "bulkwalk") == 0) {
                    592:                        if ((pdu = snmp_getbulk(agent, &noid, 1,
                    593:                            non_repeaters, max_repetitions)) == NULL)
                    594:                                err(1, "bulkwalk");
                    595:                } else {
                    596:                        if ((pdu = snmp_getnext(agent, &noid, 1)) == NULL)
                    597:                                err(1, "walk");
                    598:                }
                    599:
1.9       martijn   600:                (void) ber_scanf_elements(pdu, "t{Sdd{e", &class, &type,
                    601:                    &errorstatus, &errorindex, &varbind);
1.1       martijn   602:                if (errorstatus != 0) {
                    603:                        smi_oid2string(&noid, oidstr, sizeof(oidstr),
                    604:                            oid_lookup);
                    605:                        snmpc_printerror((enum snmp_error) errorstatus, oidstr);
                    606:                }
                    607:
1.9       martijn   608:                if (class == BER_CLASS_CONTEXT && type == SNMP_C_REPORT)
                    609:                        printf("Received report:\n");
1.2       deraadt   610:                for (; varbind != NULL; varbind = varbind->be_next) {
1.1       martijn   611:                        (void) ber_scanf_elements(varbind, "{oe}", &noid,
                    612:                            &value);
                    613:                        if (value->be_class == BER_CLASS_CONTEXT &&
                    614:                            value->be_type == BER_TYPE_EOC)
                    615:                                break;
                    616:                        prev_cmp = ber_oid_cmp(&loid, &noid);
                    617:                        if (walk_check_increase && prev_cmp == -1)
                    618:                                errx(1, "OID not increasing");
                    619:                        if (prev_cmp == 0 || ber_oid_cmp(&oid, &noid) != 2)
                    620:                                break;
                    621:                        if (walk_end.bo_n != 0 &&
                    622:                            ber_oid_cmp(&walk_end, &noid) != -1)
                    623:                                break;
                    624:
                    625:                        if (!snmpc_print(varbind))
                    626:                                err(1, "Can't print response");
                    627:                        n++;
                    628:                }
                    629:                ber_free_elements(pdu);
1.9       martijn   630:                if (class == BER_CLASS_CONTEXT && type == SNMP_C_REPORT)
                    631:                        return 1;
1.1       martijn   632:                if (varbind != NULL)
                    633:                        break;
                    634:        }
                    635:        if (walk_fallback_oid && n == 0) {
                    636:                if ((pdu = snmp_get(agent, &oid, 1)) == NULL)
                    637:                        err(1, "%s", snmp_app->name);
                    638:
1.9       martijn   639:                (void) ber_scanf_elements(pdu, "t{Sdd{e", &class, &type,
                    640:                    &errorstatus, &errorindex, &varbind);
1.1       martijn   641:                if (errorstatus != 0)
                    642:                        snmpc_printerror((enum snmp_error) errorstatus,
1.6       martijn   643:                            argv[errorindex - 1]);
1.1       martijn   644:
1.9       martijn   645:                if (class == BER_CLASS_CONTEXT && type == SNMP_C_REPORT)
                    646:                        printf("Received report:\n");
1.1       martijn   647:                if (!snmpc_print(varbind))
                    648:                        err(1, "Can't print response");
                    649:                ber_free_element(pdu);
1.9       martijn   650:                if (class == BER_CLASS_CONTEXT && type == SNMP_C_REPORT)
                    651:                        return 1;
1.1       martijn   652:                n++;
                    653:        }
                    654:        if (print_time)
                    655:                clock_gettime(CLOCK_MONOTONIC, &finish);
                    656:        if (print_summary)
                    657:                printf("Variables found: %d\n", n);
                    658:        if (print_time) {
                    659:                if ((finish.tv_nsec -= start.tv_nsec) < 0) {
                    660:                        finish.tv_sec -= 1;
                    661:                        finish.tv_nsec += 1000000000;
                    662:                }
                    663:                finish.tv_sec -= start.tv_sec;
                    664:                fprintf(stderr, "Total traversal time: %lld.%09ld seconds\n",
                    665:                    finish.tv_sec, finish.tv_nsec);
                    666:        }
                    667:        snmp_free_agent(agent);
                    668:        return 0;
                    669: }
                    670:
                    671: int
1.13    ! martijn   672: snmpc_set(int argc, char *argv[])
        !           673: {
        !           674:        struct snmp_agent *agent;
        !           675:        struct ber_element *pdu, *varbind;
        !           676:        int errorstatus, errorindex;
        !           677:        int class;
        !           678:        unsigned type;
        !           679:
        !           680:        if (argc < 4)
        !           681:                usage();
        !           682:        if ((agent = snmpc_connect(argv[0], "161")) == NULL)
        !           683:                err(1, "%s", snmp_app->name);
        !           684:        argc--;
        !           685:        argv++;
        !           686:
        !           687:        if (pledge("stdio", NULL) == -1)
        !           688:                err(1, "pledge");
        !           689:
        !           690:        pdu = snmp_set(agent, snmpc_varbindparse(argc, argv));
        !           691:
        !           692:        (void) ber_scanf_elements(pdu, "t{Sdd{e", &class, &type, &errorstatus,
        !           693:            &errorindex, &varbind);
        !           694:        if (errorstatus != 0)
        !           695:                snmpc_printerror((enum snmp_error) errorstatus,
        !           696:                    argv[errorindex - 1]);
        !           697:
        !           698:        if (class == BER_CLASS_CONTEXT && type == SNMP_C_REPORT)
        !           699:                printf("Received report:\n");
        !           700:        for (; varbind != NULL; varbind = varbind->be_next) {
        !           701:                if (!snmpc_print(varbind))
        !           702:                        err(1, "Can't print response");
        !           703:        }
        !           704:        ber_free_elements(pdu);
        !           705:        snmp_free_agent(agent);
        !           706:        return 0;
        !           707: }
        !           708:
        !           709: int
1.1       martijn   710: snmpc_trap(int argc, char *argv[])
                    711: {
                    712:        struct snmp_agent *agent;
                    713:        struct timespec ts;
1.13    ! martijn   714:        struct ber_oid trapoid;
1.1       martijn   715:        const char *errstr = NULL;
                    716:        long long lval;
                    717:
                    718:        if (version == SNMP_V1)
                    719:                errx(1, "trap is not supported for snmp v1");
                    720:
1.8       martijn   721:        if ((agent = snmpc_connect(argv[0], "162")) == NULL)
1.1       martijn   722:                err(1, "%s", snmp_app->name);
                    723:
                    724:        if (pledge("stdio", NULL) == -1)
                    725:                err(1, "pledge");
                    726:
                    727:        if (argv[1][0] == '\0') {
                    728:                if (clock_gettime(CLOCK_UPTIME, &ts) == -1)
                    729:                        err(1, "clock_gettime");
                    730:        } else {
                    731:                lval = strtonum(argv[1], 0, LLONG_MAX, &errstr);
                    732:                if (errstr != NULL)
                    733:                        errx(1, "Bad value notation (%s)", argv[1]);
                    734:                ts.tv_sec = lval / 100;
                    735:                ts.tv_nsec = (lval % 100) * 10000000;
                    736:        }
                    737:        if (smi_string2oid(argv[2], &trapoid) == -1)
                    738:                errx(1, "Invalid oid: %s\n", argv[2]);
                    739:
                    740:        argc -= 3;
                    741:        argv += 3;
                    742:
1.13    ! martijn   743:        snmp_trap(agent, &ts, &trapoid, snmpc_varbindparse(argc, argv));
1.1       martijn   744:
                    745:        return 0;
                    746: }
                    747:
                    748: int
                    749: snmpc_mibtree(int argc, char *argv[])
                    750: {
                    751:        struct oid *oid;
                    752:        char buf[BUFSIZ];
                    753:
                    754:        for (oid = NULL; (oid = smi_foreach(oid, 0)) != NULL;) {
                    755:                smi_oid2string(&oid->o_id, buf, sizeof(buf), oid_lookup);
                    756:                printf("%s\n", buf);
                    757:        }
                    758:        return 0;
1.8       martijn   759: }
                    760:
                    761: struct snmp_agent *
                    762: snmpc_connect(char *host, char *port)
                    763: {
                    764:        switch (version) {
                    765:        case SNMP_V1:
                    766:        case SNMP_V2C:
                    767:                return snmp_connect_v12(snmpc_parseagent(host, port), version,
                    768:                    community);
1.9       martijn   769:        case SNMP_V3:
                    770:                return snmp_connect_v3(snmpc_parseagent(host, port), v3);
1.8       martijn   771:        }
                    772:        return NULL;
1.1       martijn   773: }
                    774:
                    775: int
                    776: snmpc_print(struct ber_element *elm)
                    777: {
                    778:        struct ber_oid oid;
                    779:        char oids[SNMP_MAX_OID_STRLEN];
                    780:        char *value;
                    781:
                    782:        elm = elm->be_sub;
                    783:        if (ber_get_oid(elm, &oid) != 0) {
                    784:                errno = EINVAL;
                    785:                return 0;
                    786:        }
                    787:
                    788:        elm = elm->be_next;
                    789:        value = smi_print_element(elm, smi_print_hint, output_string, oid_lookup);
                    790:        if (value == NULL)
                    791:                return 0;
                    792:
                    793:        if (print_varbind_only)
                    794:                printf("%s\n", value);
                    795:        else if (print_equals) {
                    796:                smi_oid2string(&oid, oids, sizeof(oids), oid_lookup);
                    797:                printf("%s = %s\n", oids, value);
                    798:        } else {
                    799:                smi_oid2string(&oid, oids, sizeof(oids), oid_lookup);
                    800:                printf("%s %s\n", oids, value);
                    801:        }
                    802:        free(value);
1.2       deraadt   803:
1.1       martijn   804:        return 1;
                    805: }
                    806:
                    807: __dead void
                    808: snmpc_printerror(enum snmp_error error, char *oid)
                    809: {
1.2       deraadt   810:        switch (error) {
1.1       martijn   811:        case SNMP_ERROR_NONE:
                    812:                errx(1, "No error, how did I get here?");
                    813:        case SNMP_ERROR_TOOBIG:
                    814:                errx(1, "Can't parse oid %s: Response too big", oid);
                    815:        case SNMP_ERROR_NOSUCHNAME:
                    816:                errx(1, "Can't parse oid %s: No such object", oid);
                    817:        case SNMP_ERROR_BADVALUE:
                    818:                errx(1, "Can't parse oid %s: Bad value", oid);
                    819:        case SNMP_ERROR_READONLY:
                    820:                errx(1, "Can't parse oid %s: Read only", oid);
                    821:        case SNMP_ERROR_GENERR:
                    822:                errx(1, "Can't parse oid %s: Generic error", oid);
                    823:        case SNMP_ERROR_NOACCESS:
                    824:                errx(1, "Can't parse oid %s: Access denied", oid);
                    825:        case SNMP_ERROR_WRONGTYPE:
                    826:                errx(1, "Can't parse oid %s: Wrong type", oid);
                    827:        case SNMP_ERROR_WRONGLENGTH:
                    828:                errx(1, "Can't parse oid %s: Wrong length", oid);
                    829:        case SNMP_ERROR_WRONGENC:
                    830:                errx(1, "Can't parse oid %s: Wrong encoding", oid);
                    831:        case SNMP_ERROR_WRONGVALUE:
                    832:                errx(1, "Can't parse oid %s: Wrong value", oid);
                    833:        case SNMP_ERROR_NOCREATION:
                    834:                errx(1, "Can't parse oid %s: Can't be created", oid);
                    835:        case SNMP_ERROR_INCONVALUE:
                    836:                errx(1, "Can't parse oid %s: Inconsistent value", oid);
                    837:        case SNMP_ERROR_RESUNAVAIL:
                    838:                errx(1, "Can't parse oid %s: Resource unavailable", oid);
                    839:        case SNMP_ERROR_COMMITFAILED:
                    840:                errx(1, "Can't parse oid %s: Commit failed", oid);
                    841:        case SNMP_ERROR_UNDOFAILED:
                    842:                errx(1, "Can't parse oid %s: Undo faild", oid);
                    843:        case SNMP_ERROR_AUTHERROR:
                    844:                errx(1, "Can't parse oid %s: Authorization error", oid);
                    845:        case SNMP_ERROR_NOTWRITABLE:
                    846:                errx(1, "Can't parse oid %s: Not writable", oid);
                    847:        case SNMP_ERROR_INCONNAME:
                    848:                errx(1, "Can't parse oid %s: Inconsistent name", oid);
                    849:        }
                    850:        errx(1, "Can't parse oid %s: Unknown error (%d)", oid, error);
                    851: }
                    852:
                    853: int
                    854: snmpc_parseagent(char *agent, char *defaultport)
                    855: {
                    856:        struct addrinfo hints, *ai, *ai0 = NULL;
                    857:        struct sockaddr_un saddr;
                    858:        char *agentdup, *specifier, *hostname, *port = NULL;
                    859:        int error;
                    860:        int s;
                    861:
                    862:        if ((agentdup = specifier = strdup(agent)) == NULL)
                    863:                err(1, NULL);
                    864:
                    865:        bzero(&hints, sizeof(hints));
                    866:        if ((hostname = strchr(specifier, ':')) != NULL) {
                    867:                *hostname++ = '\0';
                    868:                if (strcasecmp(specifier, "udp") == 0) {
                    869:                        hints.ai_family = AF_INET;
                    870:                        hints.ai_socktype = SOCK_DGRAM;
                    871:                } else if (strcasecmp(specifier, "tcp") == 0) {
                    872:                        hints.ai_family = AF_INET;
                    873:                        hints.ai_socktype = SOCK_STREAM;
                    874:                } else if (strcasecmp(specifier, "udp6") == 0 ||
                    875:                    strcasecmp(specifier, "udpv6") == 0 ||
                    876:                    strcasecmp(specifier, "udpipv6") == 0) {
                    877:                        hints.ai_family = AF_INET6;
                    878:                        hints.ai_socktype = SOCK_DGRAM;
                    879:                } else if (strcasecmp(specifier, "tcp6") == 0 ||
                    880:                    strcasecmp(specifier, "tcpv6") == 0 ||
                    881:                    strcasecmp(specifier, "tcpipv6") == 0) {
                    882:                        hints.ai_family = AF_INET6;
                    883:                        hints.ai_socktype = SOCK_STREAM;
                    884:                } else if (strcasecmp(specifier, "unix") == 0) {
                    885:                        hints.ai_family = AF_UNIX;
                    886:                        hints.ai_socktype = SOCK_STREAM;
                    887:                        hints.ai_addr = (struct sockaddr *)&saddr;
                    888:                        hints.ai_addrlen = sizeof(saddr);
                    889:                        saddr.sun_len = sizeof(saddr);
                    890:                        saddr.sun_family = AF_UNIX;
                    891:                        if (strlcpy(saddr.sun_path, hostname,
                    892:                            sizeof(saddr.sun_path)) > sizeof(saddr.sun_path))
                    893:                                errx(1, "Hostname path too long");
                    894:                        ai = &hints;
                    895:                } else {
                    896:                        port = hostname;
                    897:                        hostname = specifier;
                    898:                        specifier = NULL;
                    899:                        hints.ai_family = AF_INET;
                    900:                        hints.ai_socktype = SOCK_DGRAM;
                    901:                }
                    902:                if (port == NULL) {
                    903:                        if (hints.ai_family == AF_INET) {
                    904:                                if ((port = strchr(hostname, ':')) != NULL)
                    905:                                        *port++ = '\0';
                    906:                        } else if (hints.ai_family == AF_INET6) {
                    907:                                if (hostname[0] == '[') {
                    908:                                        hostname++;
                    909:                                        if ((port = strchr(hostname, ']')) == NULL)
                    910:                                                errx(1, "invalid agent");
                    911:                                        *port++ = '\0';
                    912:                                        if (port[0] == ':')
                    913:                                                *port++ = '\0';
                    914:                                        else
                    915:                                                port = NULL;
                    916:                                } else {
                    917:                                        if ((port = strrchr(hostname, ':')) == NULL)
                    918:                                                errx(1, "invalid agent");
                    919:                                        *port++ = '\0';
                    920:                                }
                    921:                        }
                    922:                }
                    923:        } else {
                    924:                hostname = specifier;
                    925:                hints.ai_family = AF_INET;
                    926:                hints.ai_socktype = SOCK_DGRAM;
                    927:        }
                    928:
                    929:        if (hints.ai_family != AF_UNIX) {
                    930:                if (port == NULL)
                    931:                        port = defaultport;
                    932:                error = getaddrinfo(hostname, port, &hints, &ai0);
                    933:                if (error)
                    934:                        errx(1, "%s", gai_strerror(error));
                    935:                s = -1;
                    936:                for (ai = ai0; ai != NULL; ai = ai->ai_next) {
                    937:                        if ((s = socket(ai->ai_family, ai->ai_socktype,
                    938:                            ai->ai_protocol)) == -1)
                    939:                                continue;
                    940:                        break;
                    941:                }
                    942:        } else
                    943:                s = socket(hints.ai_family, hints.ai_socktype,
                    944:                    hints.ai_protocol);
                    945:        if (s == -1)
                    946:                err(1, "socket");
                    947:
                    948:        if (connect(s, (struct sockaddr *)ai->ai_addr, ai->ai_addrlen) == -1)
                    949:                err(1, "Can't connect to %s", agent);
                    950:
                    951:        if (ai0 != NULL)
                    952:                freeaddrinfo(ai0);
                    953:        free(agentdup);
                    954:        return s;
                    955: }
                    956:
1.9       martijn   957: char *
                    958: snmpc_hex2bin(char *hexstr, size_t *binlen)
                    959: {
                    960:        char *decstr;
                    961:
                    962:        if (hexstr[0] == '0' && hexstr[1] == 'x')
                    963:                hexstr += 2;
                    964:        while (hexstr[0] == ' ' || hexstr[0] == '\t')
                    965:                hexstr++;
                    966:
                    967:        if ((decstr = malloc((strlen(hexstr) / 2) + 1)) == NULL)
                    968:                return NULL;
                    969:
                    970:        for (*binlen = 0; hexstr[0] != '\0'; (*binlen)++) {
                    971:                hexstr[0] = toupper(hexstr[0]);
                    972:                hexstr[1] = toupper(hexstr[1]);
                    973:                if (hexstr[0] >= '0' && hexstr[0] <= '9')
                    974:                        decstr[*binlen] = (hexstr[0] - '0') << 4;
                    975:                else if (hexstr[0] >= 'A' && hexstr[0] <= 'F')
                    976:                        decstr[*binlen] = ((hexstr[0] - 'A') + 10) << 4;
                    977:                else
                    978:                        goto fail;
                    979:                if (hexstr[1] >= '0' && hexstr[1] <= '9')
                    980:                        decstr[*binlen] |= (hexstr[1] - '0');
                    981:                else if (hexstr[1] >= 'A' && hexstr[1] <= 'F')
                    982:                        decstr[*binlen] |= (hexstr[1] - 'A') + 10;
                    983:                else
                    984:                        goto fail;
                    985:
                    986:                hexstr += 2;
                    987:                while (hexstr[0] == ' ' || hexstr[0] == '\t')
                    988:                        hexstr++;
                    989:        }
                    990:
                    991:        return decstr;
                    992: fail:
                    993:        errno = EINVAL;
                    994:        free(decstr);
                    995:        return NULL;
1.13    ! martijn   996: }
        !           997:
        !           998: struct ber_element *
        !           999: snmpc_varbindparse(int argc, char *argv[])
        !          1000: {
        !          1001:        struct ber_oid oid, oidval;
        !          1002:        struct in_addr addr4;
        !          1003:        char *addr = (char *)&addr4;
        !          1004:        char *str = NULL, *tmpstr, *endstr;
        !          1005:        const char *errstr = NULL;
        !          1006:        struct ber_element *varbind = NULL, *vblist = NULL;
        !          1007:        int i, ret;
        !          1008:        size_t strl, byte;
        !          1009:        long long lval;
        !          1010:
        !          1011:        if (argc % 3 != 0)
        !          1012:                usage();
        !          1013:        for (i = 0; i < argc; i += 3) {
        !          1014:                if (smi_string2oid(argv[i], &oid) == -1)
        !          1015:                        errx(1, "Invalid oid: %s\n", argv[i]);
        !          1016:                switch (argv[i + 1][0]) {
        !          1017:                case 'a':
        !          1018:                        ret = inet_pton(AF_INET, argv[i + 2], &addr4);
        !          1019:                        if (ret == -1)
        !          1020:                                err(1, "inet_pton");
        !          1021:                        if (ret == 0)
        !          1022:                                errx(1, "%s: Bad value notation (%s)", argv[i],
        !          1023:                                    argv[i + 2]);
        !          1024:                        if ((varbind = ber_printf_elements(varbind, "{Oxt}",
        !          1025:                            &oid, addr, sizeof(addr4), BER_CLASS_APPLICATION,
        !          1026:                            SNMP_T_IPADDR)) == NULL)
        !          1027:                                err(1, "ber_printf_elements");
        !          1028:                        break;
        !          1029:                case 'b':
        !          1030:                        tmpstr = argv[i + 2];
        !          1031:                        strl = 0;
        !          1032:                        do {
        !          1033:                                lval = strtoll(tmpstr, &endstr, 10);
        !          1034:                                if (endstr[0] != ' ' && endstr[0] != '\t' &&
        !          1035:                                    endstr[0] != ',' && endstr[0] != '\0')
        !          1036:                                        errx(1, "%s: Bad value notation (%s)",
        !          1037:                                            argv[i], argv[i + 2]);
        !          1038:                                if (tmpstr == endstr) {
        !          1039:                                        tmpstr++;
        !          1040:                                        continue;
        !          1041:                                }
        !          1042:                                if (lval < 0)
        !          1043:                                        errx(1, "%s: Bad value notation (%s)",
        !          1044:                                            argv[i], argv[i + 2]);
        !          1045:                                byte = lval / 8;
        !          1046:                                if (byte >= strl) {
        !          1047:                                        if ((str = recallocarray(str, strl,
        !          1048:                                            byte + 1, 1)) == NULL)
        !          1049:                                                err(1, "malloc");
        !          1050:                                        strl = byte + 1;
        !          1051:                                }
        !          1052:                                str[byte] |= 0x80 >> (lval % 8);
        !          1053:                                tmpstr = endstr + 1;
        !          1054:                        } while (endstr[0] != '\0');
        !          1055:                        /*
        !          1056:                         * RFC3416 Section 2.5
        !          1057:                         * A BITS value is encoded as an OCTET STRING
        !          1058:                         */
        !          1059:                        goto pastestring;
        !          1060:                case 'c':
        !          1061:                        lval = strtonum(argv[i + 2], INT32_MIN, INT32_MAX,
        !          1062:                            &errstr);
        !          1063:                        if (errstr != NULL)
        !          1064:                                errx(1, "%s: Bad value notation (%s)", argv[i],
        !          1065:                                    argv[i + 2]);
        !          1066:                        if ((varbind = ber_printf_elements(varbind, "{Oit}",
        !          1067:                            &oid, lval, BER_CLASS_APPLICATION,
        !          1068:                            SNMP_T_COUNTER32)) == NULL)
        !          1069:                                err(1, "ber_printf_elements");
        !          1070:                        break;
        !          1071:                case 'd':
        !          1072:                        /* String always shrinks */
        !          1073:                        if ((str = malloc(strlen(argv[i + 2]))) == NULL)
        !          1074:                                err(1, "malloc");
        !          1075:                        tmpstr = argv[i + 2];
        !          1076:                        strl = 0;
        !          1077:                        do {
        !          1078:                                lval = strtoll(tmpstr, &endstr, 10);
        !          1079:                                if (endstr[0] != ' ' && endstr[0] != '\t' &&
        !          1080:                                    endstr[0] != '\0')
        !          1081:                                        errx(1, "%s: Bad value notation (%s)",
        !          1082:                                            argv[i], argv[i + 2]);
        !          1083:                                if (tmpstr == endstr) {
        !          1084:                                        tmpstr++;
        !          1085:                                        continue;
        !          1086:                                }
        !          1087:                                if (lval < 0 || lval > 0xff)
        !          1088:                                        errx(1, "%s: Bad value notation (%s)",
        !          1089:                                            argv[i], argv[i + 2]);
        !          1090:                                str[strl++] = (unsigned char) lval;
        !          1091:                                tmpstr = endstr + 1;
        !          1092:                        } while (endstr[0] != '\0');
        !          1093:                        goto pastestring;
        !          1094:                case 'u':
        !          1095:                case 'i':
        !          1096:                        lval = strtonum(argv[i + 2], LLONG_MIN, LLONG_MAX,
        !          1097:                            &errstr);
        !          1098:                        if (errstr != NULL)
        !          1099:                                errx(1, "%s: Bad value notation (%s)", argv[i],
        !          1100:                                    argv[i + 2]);
        !          1101:                        if ((varbind = ber_printf_elements(varbind, "{Oi}",
        !          1102:                            &oid, lval)) == NULL)
        !          1103:                                err(1, "ber_printf_elements");
        !          1104:                        break;
        !          1105:                case 'n':
        !          1106:                        if ((varbind = ber_printf_elements(varbind, "{O0}",
        !          1107:                            &oid)) == NULL)
        !          1108:                                err(1, "ber_printf_elements");
        !          1109:                        break;
        !          1110:                case 'o':
        !          1111:                        if (smi_string2oid(argv[i + 2], &oidval) == -1)
        !          1112:                                errx(1, "%s: Unknown Object Identifier (Sub-id "
        !          1113:                                    "not found: (top) -> %s)", argv[i],
        !          1114:                                    argv[i + 2]);
        !          1115:                        if ((varbind = ber_printf_elements(varbind, "{OO}",
        !          1116:                            &oid, &oidval)) == NULL)
        !          1117:                                err(1, "ber_printf_elements");
        !          1118:                        break;
        !          1119:                case 's':
        !          1120:                        if ((str = strdup(argv[i + 2])) == NULL)
        !          1121:                                err(1, NULL);
        !          1122:                        strl = strlen(argv[i + 2]);
        !          1123: pastestring:
        !          1124:                        if ((varbind = ber_printf_elements(varbind, "{Ox}",
        !          1125:                            &oid, str, strl)) == NULL)
        !          1126:                                err(1, "ber_printf_elements");
        !          1127:                        free(str);
        !          1128:                        break;
        !          1129:                case 't':
        !          1130:                        lval = strtonum(argv[i + 2], LLONG_MIN, LLONG_MAX,
        !          1131:                            &errstr);
        !          1132:                        if (errstr != NULL)
        !          1133:                                errx(1, "%s: Bad value notation (%s)", argv[i],
        !          1134:                                    argv[i + 2]);
        !          1135:                        if ((varbind = ber_printf_elements(varbind, "{Oit}",
        !          1136:                            &oid, lval, BER_CLASS_APPLICATION,
        !          1137:                            SNMP_T_TIMETICKS)) == NULL)
        !          1138:                                err(1, "ber_printf_elements");
        !          1139:                        break;
        !          1140:                case 'x':
        !          1141:                        /* String always shrinks */
        !          1142:                        if ((str = malloc(strlen(argv[i + 2]))) == NULL)
        !          1143:                                err(1, "malloc");
        !          1144:                        tmpstr = argv[i + 2];
        !          1145:                        strl = 0;
        !          1146:                        do {
        !          1147:                                lval = strtoll(tmpstr, &endstr, 16);
        !          1148:                                if (endstr[0] != ' ' && endstr[0] != '\t' &&
        !          1149:                                    endstr[0] != '\0')
        !          1150:                                        errx(1, "%s: Bad value notation (%s)",
        !          1151:                                            argv[i], argv[i + 2]);
        !          1152:                                if (tmpstr == endstr) {
        !          1153:                                        tmpstr++;
        !          1154:                                        continue;
        !          1155:                                }
        !          1156:                                if (lval < 0 || lval > 0xff)
        !          1157:                                        errx(1, "%s: Bad value notation (%s)",
        !          1158:                                            argv[i], argv[i + 2]);
        !          1159:                                str[strl++] = (unsigned char) lval;
        !          1160:                                tmpstr = endstr + 1;
        !          1161:                        } while (endstr[0] != '\0');
        !          1162:                        goto pastestring;
        !          1163:                default:
        !          1164:                        usage();
        !          1165:                }
        !          1166:                if (vblist == NULL)
        !          1167:                        vblist = varbind;
        !          1168:        }
        !          1169:
        !          1170:        return vblist;
1.9       martijn  1171: }
                   1172:
1.1       martijn  1173: __dead void
                   1174: usage(void)
                   1175: {
                   1176:        size_t i;
                   1177:
                   1178:        if (snmp_app != NULL) {
1.9       martijn  1179:                fprintf(stderr, "usage: snmp %s%s%s\n",
1.4       martijn  1180:                    snmp_app->name,
1.1       martijn  1181:                    snmp_app->usecommonopt ?
1.10      martijn  1182:                    " [-A authpass] [-a digest] [-c community] [-e secengineid]\n"
1.11      martijn  1183:                    "            [-E ctxengineid] [-K localpriv] [-k localauth] [-l seclevel]\n"
                   1184:                    "            [-n ctxname] [-O afnqvxSQ] [-r retries] [-t timeout] [-u user]\n"
                   1185:                    "            [-v version] [-X privpass] [-x cipher] [-Z boots,time]\n"
1.9       martijn  1186:                    "            " : "",
1.1       martijn  1187:                    snmp_app->usage == NULL ? "" : snmp_app->usage);
                   1188:                exit(1);
                   1189:        }
                   1190:        for (i = 0; i < (sizeof(snmp_apps)/sizeof(*snmp_apps)); i++) {
1.4       martijn  1191:                if (i == 0)
                   1192:                        fprintf(stderr, "usage: ");
                   1193:                else
                   1194:                        fprintf(stderr, "       ");
                   1195:                fprintf(stderr, "snmp %s%s %s\n",
                   1196:                    snmp_apps[i].name,
1.1       martijn  1197:                    snmp_apps[i].usecommonopt ?
1.9       martijn  1198:                    " [common options]" : "",
1.4       martijn  1199:                    snmp_apps[i].usage ? snmp_apps[i].usage : "");
1.1       martijn  1200:        }
                   1201:        exit(1);
                   1202: }