int
netsnmp_parse_args(int argc,
                   char **argv,
                   netsnmp_session * session, const char *localOpts,
                   void (*proc) (int, char *const *, int),
                   int flags)
{
    static char	   *sensitive[4] = { NULL, NULL, NULL, NULL };
    int             arg, sp = 0, testcase = 0;
    char           *cp;
    char           *Apsz = NULL;
    char           *Xpsz = NULL;
    char           *Cpsz = NULL;
    char            Opts[BUF_SIZE];
    int             zero_sensitive = !( flags & NETSNMP_PARSE_ARGS_NOZERO );

    /*
     * initialize session to default values 
     */
    snmp_sess_init(session);
    strcpy(Opts, "Y:VhHm:M:O:I:P:D:dv:r:t:c:Z:e:E:n:u:l:x:X:a:A:p:T:-:3:L:");
    if (localOpts) {
        if (strlen(localOpts) + strlen(Opts) >= sizeof(Opts)) {
            snmp_log(LOG_ERR, "Too many localOpts in snmp_parse_args()\n");
            return -1;
        }
        strcat(Opts, localOpts);
    }

    /*
     * get the options 
     */
    DEBUGMSGTL(("snmp_parse_args", "starting: %d/%d\n", optind, argc));
    for (arg = 0; arg < argc; arg++) {
        DEBUGMSGTL(("snmp_parse_args", " arg %d = %s\n", arg, argv[arg]));
    }

    optind = 1;
    while ((arg = getopt(argc, argv, Opts)) != EOF) {
        DEBUGMSGTL(("snmp_parse_args", "handling (#%d): %c\n", optind, arg));
        switch (arg) {
        case '-':
            if (strcasecmp(optarg, "help") == 0) {
                return (NETSNMP_PARSE_ARGS_ERROR_USAGE);
            }
            if (strcasecmp(optarg, "version") == 0) {
                fprintf(stderr,"NET-SNMP version: %s\n",netsnmp_get_version());
                return (NETSNMP_PARSE_ARGS_SUCCESS_EXIT);
            }

            handle_long_opt(optarg);
            break;

        case 'V':
            fprintf(stderr, "NET-SNMP version: %s\n", netsnmp_get_version());
            return (NETSNMP_PARSE_ARGS_SUCCESS_EXIT);

        case 'h':
            return (NETSNMP_PARSE_ARGS_ERROR_USAGE);
            break;

        case 'H':
            init_snmp("snmpapp");
            fprintf(stderr, "Configuration directives understood:\n");
            read_config_print_usage("  ");
            return (NETSNMP_PARSE_ARGS_SUCCESS_EXIT);

        case 'Y':
            netsnmp_config_remember(optarg);
            break;

#ifndef NETSNMP_DISABLE_MIB_LOADING
        case 'm':
            setenv("MIBS", optarg, 1);
            break;

        case 'M':
            netsnmp_get_mib_directory(); /* prepare the default directories */
            netsnmp_set_mib_directory(optarg);
            break;
#endif /* NETSNMP_DISABLE_MIB_LOADING */

        case 'O':
            cp = snmp_out_toggle_options(optarg);
            if (cp != NULL) {
                fprintf(stderr, "Unknown output option passed to -O: %c.\n", 
			*cp);
                return (NETSNMP_PARSE_ARGS_ERROR_USAGE);
            }
            break;

        case 'I':
            cp = snmp_in_options(optarg, argc, argv);
            if (cp != NULL) {
                fprintf(stderr, "Unknown input option passed to -I: %c.\n",
			*cp);
                return (NETSNMP_PARSE_ARGS_ERROR_USAGE);
            }
            break;

#ifndef NETSNMP_DISABLE_MIB_LOADING
        case 'P':
            cp = snmp_mib_toggle_options(optarg);
            if (cp != NULL) {
                fprintf(stderr,
                        "Unknown parsing option passed to -P: %c.\n", *cp);
                return (NETSNMP_PARSE_ARGS_ERROR_USAGE);
            }
            break;
#endif /* NETSNMP_DISABLE_MIB_LOADING */

        case 'D':
#ifdef NETSNMP_NO_DEBUGGING
            fprintf(stderr, "Debug not configured in\n");
            return (NETSNMP_PARSE_ARGS_ERROR_USAGE);
#else
            debug_register_tokens(optarg);
            snmp_set_do_debugging(1);
#endif
            break;

        case 'd':
            netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, 
				   NETSNMP_DS_LIB_DUMP_PACKET, 1);
            break;

        case 'v':
            session->version = -1;
#ifndef NETSNMP_DISABLE_SNMPV1
            if (!strcmp(optarg, "1")) {
                session->version = SNMP_VERSION_1;
            }
#endif
#ifndef NETSNMP_DISABLE_SNMPV2C
            if (!strcasecmp(optarg, "2c")) {
                session->version = SNMP_VERSION_2c;
            }
#endif
            if (!strcasecmp(optarg, "3")) {
                session->version = SNMP_VERSION_3;
            }
            if (session->version == -1) {
                fprintf(stderr,
                        "Invalid version specified after -v flag: %s\n",
                        optarg);
                return (NETSNMP_PARSE_ARGS_ERROR_USAGE);
            }
            break;

        case 'p':
            fprintf(stderr, "Warning: -p option is no longer used - ");
            fprintf(stderr, "specify the remote host as HOST:PORT\n");
            return (NETSNMP_PARSE_ARGS_ERROR_USAGE);
            break;

        case 'T':
        {
            char leftside[SNMP_MAXBUF_MEDIUM], rightside[SNMP_MAXBUF_MEDIUM];
            char *tmpcp, *tmpopt;
            
            /* ensure we have a proper argument */
            tmpopt = strdup(optarg);
            tmpcp = strchr(tmpopt, '=');
            if (!tmpcp) {
                fprintf(stderr, "-T expects a NAME=VALUE pair.\n");
                return (NETSNMP_PARSE_ARGS_ERROR_USAGE);
            }
            *tmpcp++ = '\0';

            /* create the transport config container if this is the first */
            if (!session->transport_configuration) {
                netsnmp_container_init_list();
                session->transport_configuration =
                    netsnmp_container_find("transport_configuration:fifo");
                if (!session->transport_configuration) {
                    fprintf(stderr, "failed to initialize the transport configuration container\n");
                    free(tmpopt);
                    return (NETSNMP_PARSE_ARGS_ERROR);
                }

                session->transport_configuration->compare =
                    (netsnmp_container_compare*)
                    netsnmp_transport_config_compare;
            }

            /* set the config */
            strlcpy(leftside, tmpopt, sizeof(leftside));
            strlcpy(rightside, tmpcp, sizeof(rightside));

            CONTAINER_INSERT(session->transport_configuration,
                             netsnmp_transport_create_config(leftside,
                                                             rightside));
            free(tmpopt);
        }
        break;
            
        case 't':
            session->timeout = (long)(atof(optarg) * 1000000L);
            if (session->timeout <= 0) {
                fprintf(stderr, "Invalid timeout in seconds after -t flag.\n");
                return (NETSNMP_PARSE_ARGS_ERROR_USAGE);
            }
            break;

        case 'r':
            session->retries = atoi(optarg);
            if (session->retries < 0 || !isdigit((unsigned char)(optarg[0]))) {
                fprintf(stderr, "Invalid number of retries after -r flag.\n");
                return (NETSNMP_PARSE_ARGS_ERROR_USAGE);
            }
            break;

        case 'c':
	    if (zero_sensitive) {
		if ((sensitive[sp] = strdup(optarg)) != NULL) {
		    Cpsz = sensitive[sp];
		    memset(optarg, '\0', strlen(optarg));
		    sp++;
		} else {
		    fprintf(stderr, "malloc failure processing -c flag.\n");
		    return NETSNMP_PARSE_ARGS_ERROR;
		}
	    } else {
		Cpsz = optarg;
	    }
            break;

        case '3':
	    /*  TODO: This needs to zero things too.  */
            if (snmpv3_options(optarg, session, &Apsz, &Xpsz, argc, argv) < 0){
                return (NETSNMP_PARSE_ARGS_ERROR_USAGE);
            }
            break;

        case 'L':
            if (snmp_log_options(optarg, argc, argv) < 0) {
                return (NETSNMP_PARSE_ARGS_ERROR_USAGE);
            }
            break;

#define SNMPV3_CMD_OPTIONS
#ifdef  SNMPV3_CMD_OPTIONS
        case 'Z':
            errno = 0;
            session->engineBoots = strtoul(optarg, &cp, 10);
            if (errno || cp == optarg) {
                fprintf(stderr, "Need engine boots value after -Z flag.\n");
                return (NETSNMP_PARSE_ARGS_ERROR_USAGE);
            }
            if (*cp == ',') {
                char *endptr;
                cp++;
                session->engineTime = strtoul(cp, &endptr, 10);
                if (errno || cp == endptr) {
                    fprintf(stderr, "Need engine time after \"-Z engineBoot,\".\n");
                    return (NETSNMP_PARSE_ARGS_ERROR_USAGE);
                }
            }
            /*
             * Handle previous '-Z boot time' syntax 
             */
            else if (optind < argc) {
                session->engineTime = strtoul(argv[optind], &cp, 10);
                if (errno || cp == argv[optind]) {
                    fprintf(stderr, "Need engine time after \"-Z engineBoot\".\n");
                    return (NETSNMP_PARSE_ARGS_ERROR_USAGE);
                }
            } else {
                fprintf(stderr, "Need engine time after \"-Z engineBoot\".\n");
                return (NETSNMP_PARSE_ARGS_ERROR_USAGE);
            }
            break;

        case 'e':{
                size_t ebuf_len = 32, eout_len = 0;
                u_char *ebuf = (u_char *)malloc(ebuf_len);

                if (ebuf == NULL) {
                    fprintf(stderr, "malloc failure processing -e flag.\n");
                    return (NETSNMP_PARSE_ARGS_ERROR);
                }
                if (!snmp_hex_to_binary
                    (&ebuf, &ebuf_len, &eout_len, 1, optarg)) {
                    fprintf(stderr, "Bad engine ID value after -e flag.\n");
                    free(ebuf);
                    return (NETSNMP_PARSE_ARGS_ERROR_USAGE);
                }
                if ((eout_len < 5) || (eout_len > 32)) {
                    fprintf(stderr, "Invalid engine ID value after -e flag.\n");
                    free(ebuf);
                    return (NETSNMP_PARSE_ARGS_ERROR_USAGE);
                }
                session->securityEngineID = ebuf;
                session->securityEngineIDLen = eout_len;
                break;
            }

        case 'E':{
                size_t ebuf_len = 32, eout_len = 0;
                u_char *ebuf = (u_char *)malloc(ebuf_len);

                if (ebuf == NULL) {
                    fprintf(stderr, "malloc failure processing -E flag.\n");
                    return (NETSNMP_PARSE_ARGS_ERROR);
                }
                if (!snmp_hex_to_binary(&ebuf, &ebuf_len,
					&eout_len, 1, optarg)) {
                    fprintf(stderr, "Bad engine ID value after -E flag.\n");
                    free(ebuf);
                    return (NETSNMP_PARSE_ARGS_ERROR_USAGE);
                }
                if ((eout_len < 5) || (eout_len > 32)) {
                    fprintf(stderr, "Invalid engine ID value after -E flag.\n");
                    free(ebuf);
                    return (NETSNMP_PARSE_ARGS_ERROR_USAGE);
                }
                session->contextEngineID = ebuf;
                session->contextEngineIDLen = eout_len;
                break;
            }

        case 'n':
            session->contextName = optarg;
            session->contextNameLen = strlen(optarg);
            break;

        case 'u':
	    if (zero_sensitive) {
		if ((sensitive[sp] = strdup(optarg)) != NULL) {
		    session->securityName = sensitive[sp];
		    session->securityNameLen = strlen(sensitive[sp]);
		    memset(optarg, '\0', strlen(optarg));
		    sp++;
		} else {
		    fprintf(stderr, "malloc failure processing -u flag.\n");
		    return NETSNMP_PARSE_ARGS_ERROR;
		}
	    } else {
		session->securityName = optarg;
		session->securityNameLen = strlen(optarg);
	    }
            break;

        case 'l':
            if (!strcasecmp(optarg, "noAuthNoPriv") || !strcmp(optarg, "1")
                || !strcasecmp(optarg, "noauth")
                || !strcasecmp(optarg, "nanp")) {
                session->securityLevel = SNMP_SEC_LEVEL_NOAUTH;
            } else if (!strcasecmp(optarg, "authNoPriv")
                       || !strcmp(optarg, "2")
                       || !strcasecmp(optarg, "auth")
                       || !strcasecmp(optarg, "anp")) {
                session->securityLevel = SNMP_SEC_LEVEL_AUTHNOPRIV;
            } else if (!strcasecmp(optarg, "authPriv")
                       || !strcmp(optarg, "3")
                       || !strcasecmp(optarg, "priv")
                       || !strcasecmp(optarg, "ap")) {
                session->securityLevel = SNMP_SEC_LEVEL_AUTHPRIV;
            } else {
                fprintf(stderr,
                        "Invalid security level specified after -l flag: %s\n",
                        optarg);
                return (NETSNMP_PARSE_ARGS_ERROR_USAGE);
            }

            break;

#ifdef NETSNMP_SECMOD_USM
        case 'a':
#ifndef NETSNMP_DISABLE_MD5
            if (!strcasecmp(optarg, "MD5")) {
                session->securityAuthProto = usmHMACMD5AuthProtocol;
                session->securityAuthProtoLen = USM_AUTH_PROTO_MD5_LEN;
            } else
#endif
                if (!strcasecmp(optarg, "SHA")) {
                session->securityAuthProto = usmHMACSHA1AuthProtocol;
                session->securityAuthProtoLen = USM_AUTH_PROTO_SHA_LEN;
            } else {
                fprintf(stderr,
                        "Invalid authentication protocol specified after -a flag: %s\n",
                        optarg);
                return (NETSNMP_PARSE_ARGS_ERROR_USAGE);
            }
            break;

        case 'x':
            testcase = 0;
#ifndef NETSNMP_DISABLE_DES
            if (!strcasecmp(optarg, "DES")) {
                testcase = 1;
                session->securityPrivProto = usmDESPrivProtocol;
                session->securityPrivProtoLen = USM_PRIV_PROTO_DES_LEN;
            }
#endif
#ifdef HAVE_AES
            if (!strcasecmp(optarg, "AES128") ||
                !strcasecmp(optarg, "AES")) {
                testcase = 1;
                session->securityPrivProto = usmAESPrivProtocol;
                session->securityPrivProtoLen = USM_PRIV_PROTO_AES_LEN;
            }
#endif
            if (testcase == 0) {
                fprintf(stderr,
                      "Invalid privacy protocol specified after -x flag: %s\n",
                        optarg);
                return (NETSNMP_PARSE_ARGS_ERROR_USAGE);
            }
            break;

        case 'A':
	    if (zero_sensitive) {
		if ((sensitive[sp] = strdup(optarg)) != NULL) {
		    Apsz = sensitive[sp];
		    memset(optarg, '\0', strlen(optarg));
		    sp++;
		} else {
		    fprintf(stderr, "malloc failure processing -A flag.\n");
		    return NETSNMP_PARSE_ARGS_ERROR;
		}
	    } else {
		Apsz = optarg;
	    }
            break;

        case 'X':
	    if (zero_sensitive) {
		if ((sensitive[sp] = strdup(optarg)) != NULL) {
		    Xpsz = sensitive[sp];
		    memset(optarg, '\0', strlen(optarg));
		    sp++;
		} else {
		    fprintf(stderr, "malloc failure processing -X flag.\n");
		    return NETSNMP_PARSE_ARGS_ERROR;
		}
	    } else {
		Xpsz = optarg;
	    }
            break;
#endif                          /* SNMPV3_CMD_OPTIONS */
#endif /* NETSNMP_SECMOD_USM */

        case '?':
            return (NETSNMP_PARSE_ARGS_ERROR_USAGE);
            break;

        default:
            proc(argc, argv, arg);
            break;
        }
    }
    DEBUGMSGTL(("snmp_parse_args", "finished: %d/%d\n", optind, argc));
    
    /*
     * read in MIB database and initialize the snmp library
     */
    init_snmp("snmpapp");

    /*
     * session default version 
     */
    if (session->version == SNMP_DEFAULT_VERSION) {
        /*
         * run time default version 
         */
        session->version = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, 
					      NETSNMP_DS_LIB_SNMPVERSION);

        /*
         * compile time default version 
         */
        if (!session->version) {
            switch (NETSNMP_DEFAULT_SNMP_VERSION) {
#ifndef NETSNMP_DISABLE_SNMPV1
            case 1:
                session->version = SNMP_VERSION_1;
                break;
#endif

#ifndef NETSNMP_DISABLE_SNMPV2C
            case 2:
                session->version = SNMP_VERSION_2c;
                break;
#endif

            case 3:
                session->version = SNMP_VERSION_3;
                break;

            default:
                snmp_log(LOG_ERR, "Can't determine a valid SNMP version for the session\n");
                return(NETSNMP_PARSE_ARGS_ERROR);
            }
        } else {
#ifndef NETSNMP_DISABLE_SNMPV1
            if (session->version == NETSNMP_DS_SNMP_VERSION_1)  /* bogus value.  version 1 actually = 0 */
                session->version = SNMP_VERSION_1;
#endif
        }
    }

#ifdef NETSNMP_SECMOD_USM
    /* XXX: this should ideally be moved to snmpusm.c somehow */

    /*
     * make master key from pass phrases 
     */
    if (Apsz) {
        session->securityAuthKeyLen = USM_AUTH_KU_LEN;
        if (session->securityAuthProto == NULL) {
            /*
             * get .conf set default 
             */
            const oid      *def =
                get_default_authtype(&session->securityAuthProtoLen);
            session->securityAuthProto =
                snmp_duplicate_objid(def, session->securityAuthProtoLen);
        }
        if (session->securityAuthProto == NULL) {
#ifndef NETSNMP_DISABLE_MD5
            /*
             * assume MD5
             */
            session->securityAuthProto =
                snmp_duplicate_objid(usmHMACMD5AuthProtocol,
                                     USM_AUTH_PROTO_MD5_LEN);
            session->securityAuthProtoLen = USM_AUTH_PROTO_MD5_LEN;
#else
            session->securityAuthProto =
                snmp_duplicate_objid(usmHMACSHA1AuthProtocol,
                                     USM_AUTH_PROTO_SHA_LEN);
            session->securityAuthProtoLen = USM_AUTH_PROTO_SHA_LEN;
#endif
        }
        if (generate_Ku(session->securityAuthProto,
                        session->securityAuthProtoLen,
                        (u_char *) Apsz, strlen(Apsz),
                        session->securityAuthKey,
                        &session->securityAuthKeyLen) != SNMPERR_SUCCESS) {
            snmp_perror(argv[0]);
            fprintf(stderr,
                    "Error generating a key (Ku) from the supplied authentication pass phrase. \n");
            return (NETSNMP_PARSE_ARGS_ERROR);
        }
    }
    if (Xpsz) {
        session->securityPrivKeyLen = USM_PRIV_KU_LEN;
        if (session->securityPrivProto == NULL) {
            /*
             * get .conf set default 
             */
            const oid      *def =
                get_default_privtype(&session->securityPrivProtoLen);
            session->securityPrivProto =
                snmp_duplicate_objid(def, session->securityPrivProtoLen);
        }
        if (session->securityPrivProto == NULL) {
            /*
             * assume DES 
             */
#ifndef NETSNMP_DISABLE_DES
            session->securityPrivProto =
                snmp_duplicate_objid(usmDESPrivProtocol,
                                     USM_PRIV_PROTO_DES_LEN);
            session->securityPrivProtoLen = USM_PRIV_PROTO_DES_LEN;
#else
            session->securityPrivProto =
                snmp_duplicate_objid(usmAESPrivProtocol,
                                     USM_PRIV_PROTO_AES_LEN);
            session->securityPrivProtoLen = USM_PRIV_PROTO_AES_LEN;
#endif

        }
        if (generate_Ku(session->securityAuthProto,
                        session->securityAuthProtoLen,
                        (u_char *) Xpsz, strlen(Xpsz),
                        session->securityPrivKey,
                        &session->securityPrivKeyLen) != SNMPERR_SUCCESS) {
            snmp_perror(argv[0]);
            fprintf(stderr,
                    "Error generating a key (Ku) from the supplied privacy pass phrase. \n");
            return (NETSNMP_PARSE_ARGS_ERROR);
        }
    }
#endif /* NETSNMP_SECMOD_USM */

    /*
     * get the hostname 
     */
    if (optind == argc) {
        fprintf(stderr, "No hostname specified.\n");
        return (NETSNMP_PARSE_ARGS_ERROR_USAGE);
    }
    session->peername = argv[optind++]; /* hostname */

#if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C)
    /*
     * If v1 or v2c, check community has been set, either by a -c option above,
     * or via a default token somewhere.  
     * If neither, it will be taken from the incoming request PDU.
     */

#if defined(NETSNMP_DISABLE_SNMPV1)
    if (session->version == SNMP_VERSION_2c)
#else 
#if defined(NETSNMP_DISABLE_SNMPV2C)
    if (session->version == SNMP_VERSION_1)
#else
    if (session->version == SNMP_VERSION_1 ||
	session->version == SNMP_VERSION_2c)
#endif
#endif
    {
        if (Cpsz == NULL) {
            Cpsz = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
					 NETSNMP_DS_LIB_COMMUNITY);
	    if (Cpsz == NULL) {
                if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
                                           NETSNMP_DS_LIB_IGNORE_NO_COMMUNITY)){
                    DEBUGMSGTL(("snmp_parse_args",
                                "ignoring that the community string is not present\n"));
                    session->community = NULL;
                    session->community_len = 0;
                } else {
                    fprintf(stderr, "No community name specified.\n");
                    return (NETSNMP_PARSE_ARGS_ERROR_USAGE);
                }
	    }
	} else {
            session->community = (unsigned char *)Cpsz;
            session->community_len = strlen(Cpsz);
        }
    }
#endif /* support for community based SNMP */

    return optind;
}
Exemple #2
0
int
snmpv3_options(char *optarg, netsnmp_session * session, char **Apsz,
               char **Xpsz, int argc, char *const *argv)
{
    char           *cp = optarg;
    int testcase;
    optarg++;
    /*
     * Support '... -3x=value ....' syntax
     */
    if (*optarg == '=') {
        optarg++;
    }
    /*
     * and '.... "-3x value" ....'  (*with* the quotes)
     */
    while (*optarg && isspace((unsigned char)(*optarg))) {
        optarg++;
    }
    /*
     * Finally, handle ".... -3x value ...." syntax
     *   (*without* surrounding quotes)
     */
    if (!*optarg) {
        /*
         * We've run off the end of the argument
         *  so move on the the next.
         */
        optarg = argv[optind++];
        if (optind > argc) {
            fprintf(stderr,
                    "Missing argument after SNMPv3 '-3%c' option.\n", *cp);
            return (-1);
        }
    }

    switch (*cp) {

    case 'Z':
        errno=0;
        session->engineBoots = strtoul(optarg, &cp, 10);
        if (errno || cp == optarg) {
            fprintf(stderr, "Need engine boots value after -3Z flag.\n");
            return (-1);
        }
        if (*cp == ',') {
            char *endptr;
            cp++;
            session->engineTime = strtoul(cp, &endptr, 10);
            if (errno || cp == endptr) {
                fprintf(stderr, "Need engine time after \"-3Z engineBoot,\".\n");
                return (-1);
            }
        } else {
            fprintf(stderr, "Need engine time after \"-3Z engineBoot,\".\n");
            return (-1);
        }
        break;

    case 'e':{
            size_t          ebuf_len = 32, eout_len = 0;
            u_char         *ebuf = (u_char *) malloc(ebuf_len);

            if (ebuf == NULL) {
                fprintf(stderr, "malloc failure processing -3e flag.\n");
                return (-1);
            }
            if (!snmp_hex_to_binary
                (&ebuf, &ebuf_len, &eout_len, 1, optarg)) {
                fprintf(stderr, "Bad engine ID value after -3e flag.\n");
                SNMP_FREE(ebuf);
                return (-1);
            }
            session->securityEngineID = ebuf;
            session->securityEngineIDLen = eout_len;
            break;
        }

    case 'E':{
            size_t          ebuf_len = 32, eout_len = 0;
            u_char         *ebuf = (u_char *) malloc(ebuf_len);

            if (ebuf == NULL) {
                fprintf(stderr, "malloc failure processing -3E flag.\n");
                return (-1);
            }
            if (!snmp_hex_to_binary
                (&ebuf, &ebuf_len, &eout_len, 1, optarg)) {
                fprintf(stderr, "Bad engine ID value after -3E flag.\n");
                SNMP_FREE(ebuf);
                return (-1);
            }
            session->contextEngineID = ebuf;
            session->contextEngineIDLen = eout_len;
            break;
        }

    case 'n':
        session->contextName = optarg;
        session->contextNameLen = strlen(optarg);
        break;

    case 'u':
        session->securityName = optarg;
        session->securityNameLen = strlen(optarg);
        break;

    case 'l':
        if (!strcasecmp(optarg, "noAuthNoPriv") || !strcmp(optarg, "1") ||
            !strcasecmp(optarg, "nanp")) {
            session->securityLevel = SNMP_SEC_LEVEL_NOAUTH;
        } else if (!strcasecmp(optarg, "authNoPriv")
                   || !strcmp(optarg, "2") || !strcasecmp(optarg, "anp")) {
            session->securityLevel = SNMP_SEC_LEVEL_AUTHNOPRIV;
        } else if (!strcasecmp(optarg, "authPriv") || !strcmp(optarg, "3")
                   || !strcasecmp(optarg, "ap")) {
            session->securityLevel = SNMP_SEC_LEVEL_AUTHPRIV;
        } else {
            fprintf(stderr,
                    "Invalid security level specified after -3l flag: %s\n",
                    optarg);
            return (-1);
        }

        break;

    case 'a':
#ifndef NETSNMP_DISABLE_MD5
        if (!strcasecmp(optarg, "MD5")) {
            session->securityAuthProto = usmHMACMD5AuthProtocol;
            session->securityAuthProtoLen = USM_AUTH_PROTO_MD5_LEN;
        } else
#endif
            if (!strcasecmp(optarg, "SHA")) {
            session->securityAuthProto = usmHMACSHA1AuthProtocol;
            session->securityAuthProtoLen = USM_AUTH_PROTO_SHA_LEN;
        } else {
            fprintf(stderr,
                    "Invalid authentication protocol specified after -3a flag: %s\n",
                    optarg);
            return (-1);
        }
        break;

    case 'x':
        testcase = 0;
#ifndef NETSNMP_DISABLE_DES
        if (!strcasecmp(optarg, "DES")) {
            session->securityPrivProto = usmDESPrivProtocol;
            session->securityPrivProtoLen = USM_PRIV_PROTO_DES_LEN;
            testcase = 1;
        }
#endif
#ifdef HAVE_AES
        if (!strcasecmp(optarg, "AES128") ||
            strcasecmp(optarg, "AES")) {
            session->securityPrivProto = usmAES128PrivProtocol;
            session->securityPrivProtoLen = USM_PRIV_PROTO_AES128_LEN;
            testcase = 1;
        }
#endif
        if (testcase == 0) {
            fprintf(stderr,
                    "Invalid privacy protocol specified after -3x flag: %s\n",
                    optarg);
            return (-1);
        }
        break;

    case 'A':
        *Apsz = optarg;
        break;

    case 'X':
        *Xpsz = optarg;
        break;

    case 'm': {
        size_t bufSize = sizeof(session->securityAuthKey);
        u_char *tmpp = session->securityAuthKey;
        if (!snmp_hex_to_binary(&tmpp, &bufSize,
                                &session->securityAuthKeyLen, 0, optarg)) {
            fprintf(stderr, "Bad key value after -3m flag.\n");
            return (-1);
        }
        break;
    }

    case 'M': {
        size_t bufSize = sizeof(session->securityPrivKey);
        u_char *tmpp = session->securityPrivKey;
        if (!snmp_hex_to_binary(&tmpp, &bufSize,
             &session->securityPrivKeyLen, 0, optarg)) {
            fprintf(stderr, "Bad key value after -3M flag.\n");
            return (-1);
        }
        break;
    }

    case 'k': {
        size_t          kbuf_len = 32, kout_len = 0;
        u_char         *kbuf = (u_char *) malloc(kbuf_len);

        if (kbuf == NULL) {
            fprintf(stderr, "malloc failure processing -3k flag.\n");
            return (-1);
        }
        if (!snmp_hex_to_binary
            (&kbuf, &kbuf_len, &kout_len, 1, optarg)) {
            fprintf(stderr, "Bad key value after -3k flag.\n");
            SNMP_FREE(kbuf);
            return (-1);
        }
        session->securityAuthLocalKey = kbuf;
        session->securityAuthLocalKeyLen = kout_len;
        break;
    }

    case 'K': {
        size_t          kbuf_len = 32, kout_len = 0;
        u_char         *kbuf = (u_char *) malloc(kbuf_len);

        if (kbuf == NULL) {
            fprintf(stderr, "malloc failure processing -3K flag.\n");
            return (-1);
        }
        if (!snmp_hex_to_binary
            (&kbuf, &kbuf_len, &kout_len, 1, optarg)) {
            fprintf(stderr, "Bad key value after -3K flag.\n");
            SNMP_FREE(kbuf);
            return (-1);
        }
        session->securityPrivLocalKey = kbuf;
        session->securityPrivLocalKeyLen = kout_len;
        break;
    }
        
    default:
        fprintf(stderr, "Unknown SNMPv3 option passed to -3: %c.\n", *cp);
        return -1;
    }
    return 0;
}
void
usm_parse_create_usmUser(const char *token, char *line)
{
    char           *cp;
    char            buf[SNMP_MAXBUF_MEDIUM];
    struct usmUser *newuser;
    u_char          userKey[SNMP_MAXBUF_SMALL], *tmpp;
    size_t          userKeyLen = SNMP_MAXBUF_SMALL;
    size_t          privKeyLen = 0;
    size_t          ret;
    int             ret2;
    int             testcase;

    newuser = usm_create_user();

    /*
     * READ: Security Name 
     */
    cp = copy_nword(line, buf, sizeof(buf));

    /*
     * might be a -e ENGINEID argument 
     */
    if (strcmp(buf, "-e") == 0) {
        size_t          ebuf_len = 32, eout_len = 0;
        u_char         *ebuf = (u_char *) malloc(ebuf_len);

        if (ebuf == NULL) {
            config_perror("malloc failure processing -e flag");
            usm_free_user(newuser);
            return;
        }

        /*
         * Get the specified engineid from the line.  
         */
        cp = copy_nword(cp, buf, sizeof(buf));
        if (!snmp_hex_to_binary(&ebuf, &ebuf_len, &eout_len, 1, buf)) {
            config_perror("invalid EngineID argument to -e");
            usm_free_user(newuser);
            SNMP_FREE(ebuf);
            return;
        }

        newuser->engineID = ebuf;
        newuser->engineIDLen = eout_len;
        cp = copy_nword(cp, buf, sizeof(buf));
    } else {
        newuser->engineID = snmpv3_generate_engineID(&ret);
        if (ret == 0) {
            usm_free_user(newuser);
            return;
        }
        newuser->engineIDLen = ret;
    }

    newuser->secName = strdup(buf);
    newuser->name = strdup(buf);

    if (!cp)
        goto add;               /* no authentication or privacy type */

    /*
     * READ: Authentication Type 
     */
#ifndef NETSNMP_DISABLE_MD5
    if (strncmp(cp, "MD5", 3) == 0) {
        memcpy(newuser->authProtocol, usmHMACMD5AuthProtocol,
               sizeof(usmHMACMD5AuthProtocol));
    } else
#endif
        if (strncmp(cp, "SHA", 3) == 0) {
        memcpy(newuser->authProtocol, usmHMACSHA1AuthProtocol,
               sizeof(usmHMACSHA1AuthProtocol));
    } else {
        config_perror("Unknown authentication protocol");
        usm_free_user(newuser);
        return;
    }

    cp = skip_token(cp);

    /*
     * READ: Authentication Pass Phrase or key
     */
    if (!cp) {
        config_perror("no authentication pass phrase");
        usm_free_user(newuser);
        return;
    }
    cp = copy_nword(cp, buf, sizeof(buf));
    if (strcmp(buf,"-m") == 0) {
        /* a master key is specified */
        cp = copy_nword(cp, buf, sizeof(buf));
        ret = sizeof(userKey);
        tmpp = userKey;
        userKeyLen = 0;
        if (!snmp_hex_to_binary(&tmpp, &ret, &userKeyLen, 0, buf)) {
            config_perror("invalid key value argument to -m");
            usm_free_user(newuser);
            return;
        }
    } else if (strcmp(buf,"-l") != 0) {
        /* a password is specified */
        userKeyLen = sizeof(userKey);
        ret2 = generate_Ku(newuser->authProtocol, newuser->authProtocolLen,
                          (u_char *) buf, strlen(buf), userKey, &userKeyLen);
        if (ret2 != SNMPERR_SUCCESS) {
            config_perror("could not generate the authentication key from the "
                          "supplied pass phrase.");
            usm_free_user(newuser);
            return;
        }
    }        
        
    /*
     * And turn it into a localized key 
     */
    ret2 = sc_get_properlength(newuser->authProtocol,
                               newuser->authProtocolLen);
    if (ret2 <= 0) {
        config_perror("Could not get proper authentication protocol key length");
	usm_free_user(newuser);
        return;
    }
    newuser->authKey = (u_char *) malloc(ret2);

    if (strcmp(buf,"-l") == 0) {
        /* a local key is directly specified */
        cp = copy_nword(cp, buf, sizeof(buf));
        newuser->authKeyLen = 0;
        ret = ret2;
        if (!snmp_hex_to_binary(&newuser->authKey, &ret,
                                &newuser->authKeyLen, 0, buf)) {
            config_perror("invalid key value argument to -l");
            usm_free_user(newuser);
            return;
        }
        if (ret != newuser->authKeyLen) {
            config_perror("improper key length to -l");
            usm_free_user(newuser);
            return;
        }
    } else {
        newuser->authKeyLen = ret2;
        ret2 = generate_kul(newuser->authProtocol, newuser->authProtocolLen,
                           newuser->engineID, newuser->engineIDLen,
                           userKey, userKeyLen,
                           newuser->authKey, &newuser->authKeyLen);
        if (ret2 != SNMPERR_SUCCESS) {
            config_perror("could not generate localized authentication key "
                          "(Kul) from the master key (Ku).");
            usm_free_user(newuser);
            return;
        }
    }

    if (!cp)
        goto add;               /* no privacy type (which is legal) */

    /*
     * READ: Privacy Type 
     */
    testcase = 0;
#ifndef NETSNMP_DISABLE_DES
    if (strncmp(cp, "DES", 3) == 0) {
        memcpy(newuser->privProtocol, usmDESPrivProtocol,
               sizeof(usmDESPrivProtocol));
        testcase = 1;
	/* DES uses a 128 bit key, 64 bits of which is a salt */
	privKeyLen = 16;
    }
#endif
#ifdef HAVE_AES
    if (strncmp(cp, "AES128", 6) == 0 ||
               strncmp(cp, "AES", 3) == 0) {
        memcpy(newuser->privProtocol, usmAESPrivProtocol,
               sizeof(usmAESPrivProtocol));
        testcase = 1;
	privKeyLen = 16;
    }
#endif
    if (testcase == 0) {
        config_perror("Unknown privacy protocol");
        usm_free_user(newuser);
        return;
    }

    cp = skip_token(cp);
    /*
     * READ: Encryption Pass Phrase or key
     */
    if (!cp) {
        /*
         * assume the same as the authentication key 
         */
        memdup(&newuser->privKey, newuser->authKey, newuser->authKeyLen);
        newuser->privKeyLen = newuser->authKeyLen;
    } else {
        cp = copy_nword(cp, buf, sizeof(buf));
        
        if (strcmp(buf,"-m") == 0) {
            /* a master key is specified */
            cp = copy_nword(cp, buf, sizeof(buf));
            ret = sizeof(userKey);
            tmpp = userKey;
            userKeyLen = 0;
            if (!snmp_hex_to_binary(&tmpp, &ret, &userKeyLen, 0, buf)) {
                config_perror("invalid key value argument to -m");
                usm_free_user(newuser);
                return;
            }
        } else if (strcmp(buf,"-l") != 0) {
            /* a password is specified */
            userKeyLen = sizeof(userKey);
            ret2 = generate_Ku(newuser->authProtocol, newuser->authProtocolLen,
                              (u_char *) buf, strlen(buf), userKey, &userKeyLen);
            if (ret2 != SNMPERR_SUCCESS) {
                config_perror("could not generate the privacy key from the "
                              "supplied pass phrase.");
                usm_free_user(newuser);
                return;
            }
        }        
        
        /*
         * And turn it into a localized key 
         */
        ret2 = sc_get_properlength(newuser->authProtocol,
                                   newuser->authProtocolLen);
        if (ret2 < 0) {
            config_perror("could not get proper key length to use for the "
                          "privacy algorithm.");
            usm_free_user(newuser);
            return;
        }
        newuser->privKey = (u_char *) malloc(ret2);

        if (strcmp(buf,"-l") == 0) {
            /* a local key is directly specified */
            cp = copy_nword(cp, buf, sizeof(buf));
            ret = ret2;
            newuser->privKeyLen = 0;
            if (!snmp_hex_to_binary(&newuser->privKey, &ret,
                                    &newuser->privKeyLen, 0, buf)) {
                config_perror("invalid key value argument to -l");
                usm_free_user(newuser);
                return;
            }
        } else {
            newuser->privKeyLen = ret2;
            ret2 = generate_kul(newuser->authProtocol, newuser->authProtocolLen,
                               newuser->engineID, newuser->engineIDLen,
                               userKey, userKeyLen,
                               newuser->privKey, &newuser->privKeyLen);
            if (ret2 != SNMPERR_SUCCESS) {
                config_perror("could not generate localized privacy key "
                              "(Kul) from the master key (Ku).");
                usm_free_user(newuser);
                return;
            }
        }
    }

    if ((newuser->privKeyLen >= privKeyLen) || (privKeyLen == 0)){
      newuser->privKeyLen = privKeyLen;
    }
    else {
      /* The privKey length is smaller than required by privProtocol */
      usm_free_user(newuser);
      return;
    }

  add:
    usm_add_user(newuser);
    DEBUGMSGTL(("usmUser", "created a new user %s at ", newuser->secName));
    DEBUGMSGHEX(("usmUser", newuser->engineID, newuser->engineIDLen));
    DEBUGMSG(("usmUser", "\n"));
}
Exemple #4
0
int
_load_v6(netsnmp_container *container, int idx_offset)
{
    FILE           *in;
    char            line[80], addr[33], if_name[IFNAMSIZ];
    u_char          *buf;
    int             if_index, pfx_len, scope, flags, rc = 0, in_len, out_len;
    netsnmp_ipaddress_entry *entry;
    _ioctl_extras           *extras;
    static int      log_open_err = 1;
    
    netsnmp_assert(NULL != container);

#define PROCFILE "/proc/net/if_inet6"
    if (!(in = fopen(PROCFILE, "r"))) {
        if (1 == log_open_err) {
            snmp_log(LOG_ERR,"could not open " PROCFILE "\n");
            log_open_err = 0;
        }
        return -2;
    }
    /*
     * if we hadn't been able to open file and turned of err logging,
     * turn it back on now that we opened the file.
     */
    if (0 == log_open_err)
        log_open_err = 1;

    /*
     * address index prefix_len scope status if_name
     */
    while (fgets(line, sizeof(line), in)) {
        /*
         * fe800000000000000200e8fffe5b5c93 05 40 20 80 eth0
         *             A                    D  P  S  F  I
         * A: address
         * D: device number
         * P: prefix len
         * S: scope (see include/net/ipv6.h, net/ipv6/addrconf.c)
         * F: flags (see include/linux/rtnetlink.h, net/ipv6/addrconf.c)
         * I: interface
         */
        rc = sscanf(line, "%32s %02x %02x %02x %02x %8s\n",
                    addr, &if_index, &pfx_len, &scope, &flags, if_name);
        if( 6 != rc ) {
            snmp_log(LOG_ERR, PROCFILE " data format error (%d!=6), line ==|%s|\n",
                     rc, line);
            continue;
        }
        DEBUGMSGTL(("access:ipaddress:container",
                    "addr %s, index %d, pfx %d, scope %d, flags 0x%X, name %s\n",
                    addr, if_index, pfx_len, scope, flags, if_name));
        /*
         */
        entry = netsnmp_access_ipaddress_entry_create();
        if(NULL == entry) {
            rc = -3;
            break;
        }

        in_len = entry->ia_address_len = sizeof(entry->ia_address);
        netsnmp_assert(16 == in_len);
        out_len = 0;
        buf = entry->ia_address;
        if(1 != snmp_hex_to_binary(&buf,
                                   &in_len, &out_len, 0, addr)) {
            snmp_log(LOG_ERR,"error parsing '%s', skipping\n",
                     entry->ia_address);
            netsnmp_access_ipaddress_entry_free(entry);
            continue;
        }
        netsnmp_assert(16 == out_len);
        entry->ia_address_len = out_len;

        entry->ns_ia_index = ++idx_offset;

        /*
         * save if name
         */
        extras = netsnmp_ioctl_ipaddress_extras_get(entry);
        memcpy(extras->name, if_name, sizeof(extras->name));
        extras->flags = flags;

        /*
         * yyy-rks: optimization: create a socket outside the loop and use
         * netsnmp_access_interface_ioctl_ifindex_get() here, since
         * netsnmp_access_interface_index_find will open/close a socket
         * every time it is called.
         */
        entry->if_index = netsnmp_access_interface_index_find(if_name);

        /*
          #define IPADDRESSSTATUSTC_PREFERRED  1
          #define IPADDRESSSTATUSTC_DEPRECATED  2
          #define IPADDRESSSTATUSTC_INVALID  3
          #define IPADDRESSSTATUSTC_INACCESSIBLE  4
          #define IPADDRESSSTATUSTC_UNKNOWN  5
          #define IPADDRESSSTATUSTC_TENTATIVE  6
          #define IPADDRESSSTATUSTC_DUPLICATE  7
        */
        if(flags & IFA_F_PERMANENT)
            entry->ia_status = IPADDRESSSTATUSTC_PREFERRED; /* ?? */
        else if(flags & IFA_F_DEPRECATED)
            entry->ia_status = IPADDRESSSTATUSTC_DEPRECATED;
        else if(flags & IFA_F_TENTATIVE)
            entry->ia_status = IPADDRESSSTATUSTC_TENTATIVE;
        else {
            entry->ia_status = IPADDRESSSTATUSTC_UNKNOWN;
            DEBUGMSGTL(("access:ipaddress:ipv6",
                        "unknown flags 0x%x\n", flags));
        }

        /*
         * if it's not multi, it must be uni.
         *  (an ipv6 address is never broadcast)
         */
        if (IN6_IS_ADDR_MULTICAST(entry->ia_address))
            entry->ia_type = IPADDRESSTYPE_ANYCAST;
        else
            entry->ia_type = IPADDRESSTYPE_UNICAST;


        /** entry->ia_prefix_oid ? */

        /*
         * can we figure out if an address is from DHCP?
         * use manual until then...
         *
         *#define IPADDRESSORIGINTC_OTHER  1
         *#define IPADDRESSORIGINTC_MANUAL  2
         *#define IPADDRESSORIGINTC_DHCP  4
         *#define IPADDRESSORIGINTC_LINKLAYER  5
         *#define IPADDRESSORIGINTC_RANDOM  6
         *
         * are 'local' address assigned by link layer??
         */
        if (IN6_IS_ADDR_LINKLOCAL(entry->ia_address) ||
            IN6_IS_ADDR_SITELOCAL(entry->ia_address))
            entry->ia_origin = IPADDRESSORIGINTC_LINKLAYER;
        else
            entry->ia_origin = IPADDRESSORIGINTC_MANUAL;

        /* xxx-rks: what can we do with scope? */

        /*
         * add entry to container
         */
        CONTAINER_INSERT(container, entry);
    }

    fclose(in);

    if(rc<0)
        return rc;

    return idx_offset;
}
Exemple #5
0
int
main(int argc, char *argv[])
{
    netsnmp_session session, *ss;
    netsnmp_pdu    *pdu = NULL, *response = NULL;

    int             arg;
    size_t          name_length = USM_OID_LEN;
    size_t          name_length2 = USM_OID_LEN;
    int             status;
    int             exitval = 0;
    int             rval;
    int             command = 0;
    long            longvar;

    size_t          oldKu_len = SNMP_MAXBUF_SMALL,
        newKu_len = SNMP_MAXBUF_SMALL,
        oldkul_len = SNMP_MAXBUF_SMALL,
        oldkulpriv_len = SNMP_MAXBUF_SMALL,
        newkulpriv_len = SNMP_MAXBUF_SMALL,
        newkul_len = SNMP_MAXBUF_SMALL,
        keychange_len = SNMP_MAXBUF_SMALL,
        keychangepriv_len = SNMP_MAXBUF_SMALL;

    char           *newpass = NULL, *oldpass = NULL;
    u_char          oldKu[SNMP_MAXBUF_SMALL],
        newKu[SNMP_MAXBUF_SMALL],
        oldkul[SNMP_MAXBUF_SMALL],
        oldkulpriv[SNMP_MAXBUF_SMALL],
        newkulpriv[SNMP_MAXBUF_SMALL],
        newkul[SNMP_MAXBUF_SMALL], keychange[SNMP_MAXBUF_SMALL],
        keychangepriv[SNMP_MAXBUF_SMALL];

    authKeyChange = authKeyOid;
    privKeyChange = privKeyOid;

    /*
     * get the common command line arguments 
     */
    switch (arg = snmp_parse_args(argc, argv, &session, "C:", optProc)) {
    case -2:
        exit(0);
    case -1:
        usage();
        exit(1);
    default:
        break;
    }

    if (arg >= argc) {
        fprintf(stderr, "Please specify an operation to perform.\n");
        usage();
        exit(1);
    }

    SOCK_STARTUP;

    /*
     * open an SNMP session 
     */
    /*
     * Note:  this needs to obtain the engineID used below 
     */
    session.flags &= ~SNMP_FLAGS_DONT_PROBE;
    ss = snmp_open(&session);
    if (ss == NULL) {
        /*
         * diagnose snmp_open errors with the input netsnmp_session pointer 
         */
        snmp_sess_perror("snmpusm", &session);
        exit(1);
    }

    /*
     * set usmUserEngineID from ss->contextEngineID
     *   if not already set (via -CE)
     */
    if (usmUserEngineID == NULL) {
      usmUserEngineID    = ss->contextEngineID;
      usmUserEngineIDLen = ss->contextEngineIDLen;
    }

    /*
     * create PDU for SET request and add object names and values to request 
     */
    pdu = snmp_pdu_create(SNMP_MSG_SET);
    if (!pdu) {
        fprintf(stderr, "Failed to create request\n");
        exit(1);
    }


    if (strcmp(argv[arg], CMD_PASSWD_NAME) == 0) {

        /*
         * passwd: change a users password.
         *
         * XXX:  Uses the auth type of the calling user, a MD5 user can't
         *       change a SHA user's key.
         */
        char *passwd_user;

        command = CMD_PASSWD;
        oldpass = argv[++arg];
        newpass = argv[++arg];
        passwd_user = argv[++arg];

        if (doprivkey == 0 && doauthkey == 0)
            doprivkey = doauthkey = 1;

        if (newpass == NULL || strlen(newpass) < USM_LENGTH_P_MIN) {
            fprintf(stderr,
                    "New passphrase must be greater than %d characters in length.\n",
                    USM_LENGTH_P_MIN);
            exit(1);
        }

        if (oldpass == NULL || strlen(oldpass) < USM_LENGTH_P_MIN) {
            fprintf(stderr,
                    "Old passphrase must be greater than %d characters in length.\n",
                    USM_LENGTH_P_MIN);
            exit(1);
        }

        /* 
         * Change the user supplied on command line.
         */
        if ((passwd_user != NULL) && (strlen(passwd_user) > 0)) {
            session.securityName = passwd_user;
        } else {
            /*
             * Use own key object if no user was supplied.
             */
            authKeyChange = ownAuthKeyOid;
            privKeyChange = ownPrivKeyOid;
        }

        /*
         * do we have a securityName?  If not, copy the default 
         */
        if (session.securityName == NULL) {
            session.securityName = 
	      strdup(netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
					   NETSNMP_DS_LIB_SECNAME));
        }

        /*
         * the old Ku is in the session, but we need the new one 
         */
        if (session.securityAuthProto == NULL) {
            /*
             * get .conf set default 
             */
            const oid      *def =
                get_default_authtype(&session.securityAuthProtoLen);
            session.securityAuthProto =
                snmp_duplicate_objid(def, session.securityAuthProtoLen);
        }
        if (session.securityAuthProto == NULL) {
            /*
             * assume MD5 
             */
#ifndef NETSNMP_DISABLE_MD5
            session.securityAuthProtoLen =
                sizeof(usmHMACMD5AuthProtocol) / sizeof(oid);
            session.securityAuthProto =
                snmp_duplicate_objid(usmHMACMD5AuthProtocol,
                                     session.securityAuthProtoLen);
#else
            session.securityAuthProtoLen =
                sizeof(usmHMACSHA1AuthProtocol) / sizeof(oid);
            session.securityAuthProto =
                snmp_duplicate_objid(usmHMACSHA1AuthProtocol,
                                     session.securityAuthProtoLen);
#endif

        }

	if (uselocalizedkey && (strncmp(oldpass, "0x", 2) == 0)) {
	    /*
	     * use the localized key from the command line
	     */
	    u_char *buf;
	    size_t buf_len = SNMP_MAXBUF_SMALL;
	    buf = (u_char *) malloc (buf_len * sizeof(u_char));

	    oldkul_len = 0; /* initialize the offset */
	    if (!snmp_hex_to_binary((u_char **) (&buf), &buf_len, &oldkul_len, 0, oldpass)) {
	      snmp_perror(argv[0]);
	      fprintf(stderr, "generating the old Kul from localized key failed\n");
	      exit(1);
	    }
	    
	    memcpy(oldkul, buf, oldkul_len);
	    SNMP_FREE(buf);
	}
	else {
	    /*
	     * the old Ku is in the session, but we need the new one 
	     */
	    rval = generate_Ku(session.securityAuthProto,
			       session.securityAuthProtoLen,
			       (u_char *) oldpass, strlen(oldpass),
			       oldKu, &oldKu_len);
	    
	    if (rval != SNMPERR_SUCCESS) {
	        snmp_perror(argv[0]);
	        fprintf(stderr, "generating the old Ku failed\n");
	        exit(1);
	    }

	    /*
	     * generate the two Kul's 
	     */
	    rval = generate_kul(session.securityAuthProto,
				session.securityAuthProtoLen,
				usmUserEngineID, usmUserEngineIDLen,
				oldKu, oldKu_len, oldkul, &oldkul_len);
	    
	    if (rval != SNMPERR_SUCCESS) {
	        snmp_perror(argv[0]);
		fprintf(stderr, "generating the old Kul failed\n");
		exit(1);
	    }
	}
	if (uselocalizedkey && (strncmp(newpass, "0x", 2) == 0)) {
	    /*
	     * use the localized key from the command line
	     */
	    u_char *buf;
	    size_t buf_len = SNMP_MAXBUF_SMALL;
	    buf = (u_char *) malloc (buf_len * sizeof(u_char));

	    newkul_len = 0; /* initialize the offset */
	    if (!snmp_hex_to_binary((u_char **) (&buf), &buf_len, &newkul_len, 0, newpass)) {
	      snmp_perror(argv[0]);
	      fprintf(stderr, "generating the new Kul from localized key failed\n");
	      exit(1);
	    }
	    
	    memcpy(newkul, buf, newkul_len);
	    SNMP_FREE(buf);
	} else {
            rval = generate_Ku(session.securityAuthProto,
                               session.securityAuthProtoLen,
                               (u_char *) newpass, strlen(newpass),
                               newKu, &newKu_len);

            if (rval != SNMPERR_SUCCESS) {
                snmp_perror(argv[0]);
                fprintf(stderr, "generating the new Ku failed\n");
                exit(1);
            }

	    rval = generate_kul(session.securityAuthProto,
				session.securityAuthProtoLen,
				usmUserEngineID, usmUserEngineIDLen,
				newKu, newKu_len, newkul, &newkul_len);

	    if (rval != SNMPERR_SUCCESS) {
	        snmp_perror(argv[0]);
		fprintf(stderr, "generating the new Kul failed\n");
		exit(1);
	    }
	}

        /*
         * for encryption, we may need to truncate the key to the proper length
         * so we need two copies.  For simplicity, we always just copy even if
         * they're the same lengths.
         */
        if (doprivkey) {
            if (!session.securityPrivProto) {
                snmp_log(LOG_ERR, "no encryption type specified, which I need in order to know to change the key\n");
                exit(1);
            }
                
#ifndef NETSNMP_DISABLE_DES
            if (ISTRANSFORM(session.securityPrivProto, DESPriv)) {
                /* DES uses a 128 bit key, 64 bits of which is a salt */
                oldkulpriv_len = newkulpriv_len = 16;
            }
#endif
#ifdef HAVE_AES
            if (ISTRANSFORM(session.securityPrivProto, AESPriv)) {
                oldkulpriv_len = newkulpriv_len = 16;
            }
#endif
            memcpy(oldkulpriv, oldkul, oldkulpriv_len);
            memcpy(newkulpriv, newkul, newkulpriv_len);
        }
            

        /*
         * create the keychange string 
         */
	if (doauthkey) {
	  rval = encode_keychange(session.securityAuthProto,
				  session.securityAuthProtoLen,
				  oldkul, oldkul_len,
				  newkul, newkul_len,
				  keychange, &keychange_len);

	  if (rval != SNMPERR_SUCCESS) {
	    snmp_perror(argv[0]);
            fprintf(stderr, "encoding the keychange failed\n");
            usage();
            exit(1);
	  }
	}

        /* which is slightly different for encryption if lengths are
           different */
	if (doprivkey) {
	  rval = encode_keychange(session.securityAuthProto,
                                session.securityAuthProtoLen,
                                oldkulpriv, oldkulpriv_len,
                                newkulpriv, newkulpriv_len,
                                keychangepriv, &keychangepriv_len);

	  if (rval != SNMPERR_SUCCESS) {
            snmp_perror(argv[0]);
            fprintf(stderr, "encoding the keychange failed\n");
            usage();
            exit(1);
	  }
	}

        /*
         * add the keychange string to the outgoing packet 
         */
        if (doauthkey) {
            setup_oid(authKeyChange, &name_length,
                      usmUserEngineID, usmUserEngineIDLen,
                      session.securityName);
            snmp_pdu_add_variable(pdu, authKeyChange, name_length,
                                  ASN_OCTET_STR, keychange, keychange_len);
        }
        if (doprivkey) {
            setup_oid(privKeyChange, &name_length2,
                      usmUserEngineID, usmUserEngineIDLen,
                      session.securityName);
            snmp_pdu_add_variable(pdu, privKeyChange, name_length2,
                                  ASN_OCTET_STR,
                                  keychangepriv, keychangepriv_len);
        }

    } else if (strcmp(argv[arg], CMD_CREATE_NAME) == 0) {
        /*
         * create:  create a user
         *
         * create USER [CLONEFROM]
         */
        if (++arg >= argc) {
            fprintf(stderr, "You must specify the user name to create\n");
            usage();
            exit(1);
        }

        command = CMD_CREATE;

        if (++arg < argc) {
            /*
             * clone the new user from an existing user
             *   (and make them active immediately)
             */
            setup_oid(usmUserStatus, &name_length,
                      usmUserEngineID, usmUserEngineIDLen, argv[arg-1]);
            longvar = RS_CREATEANDGO;
            snmp_pdu_add_variable(pdu, usmUserStatus, name_length,
                                  ASN_INTEGER, (u_char *) & longvar,
                                  sizeof(longvar));

            name_length = USM_OID_LEN;
            setup_oid(usmUserCloneFrom, &name_length,
                      usmUserEngineID, usmUserEngineIDLen,
                      argv[arg - 1]);
            setup_oid(usmUserSecurityName, &name_length2,
                      usmUserEngineID, usmUserEngineIDLen,
                      argv[arg]);
            snmp_pdu_add_variable(pdu, usmUserCloneFrom, name_length,
                                  ASN_OBJECT_ID,
                                  (u_char *) usmUserSecurityName,
                                  sizeof(oid) * name_length2);
        } else {
            /*
             * create a new (unauthenticated) user from scratch
             * The Net-SNMP agent won't allow such a user to be made active.
             */
            setup_oid(usmUserStatus, &name_length,
                      usmUserEngineID, usmUserEngineIDLen, argv[arg-1]);
            longvar = RS_CREATEANDWAIT;
            snmp_pdu_add_variable(pdu, usmUserStatus, name_length,
                                  ASN_INTEGER, (u_char *) & longvar,
                                  sizeof(longvar));
        }

    } else if (strcmp(argv[arg], CMD_CLONEFROM_NAME) == 0) {
        /*
         * create:  clone a user from another
         *
         * cloneFrom USER FROM
         */
        if (++arg >= argc) {
            fprintf(stderr,
                    "You must specify the user name to operate on\n");
            usage();
            exit(1);
        }

        command = CMD_CLONEFROM;
        setup_oid(usmUserStatus, &name_length,
                  usmUserEngineID, usmUserEngineIDLen, argv[arg]);
        longvar = RS_ACTIVE;
        snmp_pdu_add_variable(pdu, usmUserStatus, name_length,
                              ASN_INTEGER, (u_char *) & longvar,
                              sizeof(longvar));
        name_length = USM_OID_LEN;
        setup_oid(usmUserCloneFrom, &name_length,
                  usmUserEngineID, usmUserEngineIDLen, argv[arg]);

        if (++arg >= argc) {
            fprintf(stderr,
                    "You must specify the user name to clone from\n");
            usage();
            exit(1);
        }

        setup_oid(usmUserSecurityName, &name_length2,
                  usmUserEngineID, usmUserEngineIDLen, argv[arg]);
        snmp_pdu_add_variable(pdu, usmUserCloneFrom, name_length,
                              ASN_OBJECT_ID,
                              (u_char *) usmUserSecurityName,
                              sizeof(oid) * name_length2);

    } else if (strcmp(argv[arg], CMD_DELETE_NAME) == 0) {
        /*
         * delete:  delete a user
         *
         * delete USER
         */
        if (++arg >= argc) {
            fprintf(stderr, "You must specify the user name to delete\n");
            exit(1);
        }

        command = CMD_DELETE;
        setup_oid(usmUserStatus, &name_length,
                  usmUserEngineID, usmUserEngineIDLen, argv[arg]);
        longvar = RS_DESTROY;
        snmp_pdu_add_variable(pdu, usmUserStatus, name_length,
                              ASN_INTEGER, (u_char *) & longvar,
                              sizeof(longvar));
    } else if (strcmp(argv[arg], CMD_ACTIVATE_NAME) == 0) {
        /*
         * activate:  activate a user
         *
         * activate USER
         */
        if (++arg >= argc) {
            fprintf(stderr, "You must specify the user name to activate\n");
            exit(1);
        }

        command = CMD_ACTIVATE;
        setup_oid(usmUserStatus, &name_length,
                  usmUserEngineID, usmUserEngineIDLen, argv[arg]);
        longvar = RS_ACTIVE;
        snmp_pdu_add_variable(pdu, usmUserStatus, name_length,
                              ASN_INTEGER, (u_char *) & longvar,
                              sizeof(longvar));
    } else if (strcmp(argv[arg], CMD_DEACTIVATE_NAME) == 0) {
        /*
         * deactivate:  deactivate a user
         *
         * deactivate USER
         */
        if (++arg >= argc) {
            fprintf(stderr, "You must specify the user name to deactivate\n");
            exit(1);
        }

        command = CMD_DEACTIVATE;
        setup_oid(usmUserStatus, &name_length,
                  usmUserEngineID, usmUserEngineIDLen, argv[arg]);
        longvar = RS_NOTINSERVICE;
        snmp_pdu_add_variable(pdu, usmUserStatus, name_length,
                              ASN_INTEGER, (u_char *) & longvar,
                              sizeof(longvar));
#if defined(HAVE_OPENSSL_DH_H) && defined(HAVE_LIBCRYPTO)
    } else if (strcmp(argv[arg], CMD_CHANGEKEY_NAME) == 0) {
        /*
         * change the key of a user if DH is available
         */

        char *passwd_user;
        netsnmp_pdu *dhpdu, *dhresponse = NULL;
        netsnmp_variable_list *vars, *dhvar;
        
        command = CMD_CHANGEKEY;
        name_length = DH_USM_OID_LEN;
        name_length2 = DH_USM_OID_LEN;

        passwd_user = argv[++arg];

        if (doprivkey == 0 && doauthkey == 0)
            doprivkey = doauthkey = 1;

        /* 
         * Change the user supplied on command line.
         */
        if ((passwd_user != NULL) && (strlen(passwd_user) > 0)) {
            session.securityName = passwd_user;
        } else {
            /*
             * Use own key object if no user was supplied.
             */
            dhauthKeyChange = usmDHUserOwnAuthKeyChange;
            dhprivKeyChange = usmDHUserOwnPrivKeyChange;
        }

        /*
         * do we have a securityName?  If not, copy the default 
         */
        if (session.securityName == NULL) {
            session.securityName = 
	      strdup(netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
					   NETSNMP_DS_LIB_SECNAME));
        }

        /* fetch the needed diffie helman parameters */
        dhpdu = snmp_pdu_create(SNMP_MSG_GET);
        if (!dhpdu) {
            fprintf(stderr, "Failed to create DH request\n");
            exit(1);
        }

        /* get the current DH parameters */
        snmp_add_null_var(dhpdu, usmDHParameters, usmDHParameters_len);
        
        /* maybe the auth key public value */
        if (doauthkey) {
            setup_oid(dhauthKeyChange, &name_length,
                      usmUserEngineID, usmUserEngineIDLen,
                      session.securityName);
            snmp_add_null_var(dhpdu, dhauthKeyChange, name_length);
        }
            
        /* maybe the priv key public value */
        if (doprivkey) {
            setup_oid(dhprivKeyChange, &name_length2,
                      usmUserEngineID, usmUserEngineIDLen,
                      session.securityName);
            snmp_add_null_var(dhpdu, dhprivKeyChange, name_length2);
        }

        /* fetch the values */
        status = snmp_synch_response(ss, dhpdu, &dhresponse);

        if (status != SNMPERR_SUCCESS || dhresponse == NULL ||
            dhresponse->errstat != SNMP_ERR_NOERROR ||
            dhresponse->variables->type != ASN_OCTET_STR) {
            snmp_sess_perror("snmpusm", ss);
            if (dhresponse && dhresponse->variables &&
                dhresponse->variables->type != ASN_OCTET_STR) {
                fprintf(stderr,
                        "Can't get diffie-helman exchange from the agent\n");
                fprintf(stderr,
                        "  (maybe it doesn't support the SNMP-USM-DH-OBJECTS-MIB MIB)\n");
            }
            exitval = 1;
            goto begone;
        }
        
        dhvar = dhresponse->variables;
        vars = dhvar->next_variable;
        /* complete the DH equation & print resulting keys */
        if (doauthkey) {
            if (get_USM_DH_key(vars, dhvar,
                               sc_get_properlength(ss->securityAuthProto,
                                                   ss->securityAuthProtoLen),
                               pdu, "auth",
                               dhauthKeyChange, name_length) != SNMPERR_SUCCESS)
                goto begone;
            vars = vars->next_variable;
        }
        if (doprivkey) {
	    size_t dhprivKeyLen = 0;
#ifndef NETSNMP_DISABLE_DES
	    if (ISTRANSFORM(ss->securityPrivProto, DESPriv)) {
                /* DES uses a 128 bit key, 64 bits of which is a salt */
	        dhprivKeyLen = 16;
	    }
#endif
#ifdef HAVE_AES
	    if (ISTRANSFORM(ss->securityPrivProto, AESPriv)) {
	        dhprivKeyLen = 16;
	    }
#endif
            if (get_USM_DH_key(vars, dhvar,
                               dhprivKeyLen,
                               pdu, "priv",
                               dhprivKeyChange, name_length2)
                != SNMPERR_SUCCESS)
                goto begone;
            vars = vars->next_variable;
        }
        /* snmp_free_pdu(dhresponse); */ /* parts still in use somewhere */
#endif /* HAVE_OPENSSL_DH_H */
    } else {
        fprintf(stderr, "Unknown command\n");
        usage();
        exit(1);
    }

    /*
     * add usmUserPublic if specified (via -Cp)
     */
    if (usmUserPublic_val) {
        name_length = USM_OID_LEN;
	setup_oid(usmUserPublic, &name_length,
		  usmUserEngineID, usmUserEngineIDLen,
		  session.securityName);
	snmp_pdu_add_variable(pdu, usmUserPublic, name_length,
			      ASN_OCTET_STR, usmUserPublic_val, 
			      strlen(usmUserPublic_val));	  
    }

    /*
     * do the request 
     */
    status = snmp_synch_response(ss, pdu, &response);
    if (status == STAT_SUCCESS) {
        if (response) {
            if (response->errstat == SNMP_ERR_NOERROR) {
                fprintf(stdout, "%s\n", successNotes[command - 1]);
            } else {
                fprintf(stderr, "Error in packet.\nReason: %s\n",
                        snmp_errstring(response->errstat));
                if (response->errindex != 0) {
                    int             count;
                    netsnmp_variable_list *vars;
                    fprintf(stderr, "Failed object: ");
                    for (count = 1, vars = response->variables;
                         vars && count != response->errindex;
                         vars = vars->next_variable, count++)
                        /*EMPTY*/;
                    if (vars)
                        fprint_objid(stderr, vars->name,
                                     vars->name_length);
                    fprintf(stderr, "\n");
                }
                exitval = 2;
            }
        }
    } else if (status == STAT_TIMEOUT) {
        fprintf(stderr, "Timeout: No Response from %s\n",
                session.peername);
        exitval = 1;
    } else {                    /* status == STAT_ERROR */
        snmp_sess_perror("snmpset", ss);
        exitval = 1;
    }

  begone:
    if (response)
        snmp_free_pdu(response);
    snmp_close(ss);
    SOCK_CLEANUP;
    return exitval;
}
Exemple #6
0
static void
optProc(int argc, char *const *argv, int opt)
{
    switch (opt) {
    case 'C':
        while (*optarg) {
            switch (*optarg++) {
            case 'a':
                doauthkey = 1;
                break;

            case 'x':
                doprivkey = 1;
                break;

	    case 'k':
	        uselocalizedkey = 1;
		break;

	    case 'p':
                if (optind < argc) {
		    usmUserPublic_val =  argv[optind];
                } else {
                    fprintf(stderr, "Bad -Cp option: no argument given\n");
                    exit(1);
                }
                optind++;
                break;

	    case 'E': {
	        size_t ebuf_len = 32; /* XXX: MAX_ENGINEID_LENGTH */
                u_char *ebuf;
                if (optind < argc) {
                    if (argv[optind]) {
                        ebuf = (u_char *)malloc(ebuf_len);
                        if (ebuf == NULL) {
                            fprintf(stderr, 
                                    "malloc failure processing -CE option.\n");
                            exit(1);
                        }
		        if (!snmp_hex_to_binary(&ebuf, &ebuf_len,
                                                &usmUserEngineIDLen, 1, argv[optind])) {
                            fprintf(stderr, 
                                    "Bad usmUserEngineID value after -CE option.\n");
		            free(ebuf);
		            exit(1);
		        }
		        usmUserEngineID = ebuf;
		        DEBUGMSGTL(("snmpusm", "usmUserEngineID set to: "));
		        DEBUGMSGHEX(("snmpusm", usmUserEngineID, usmUserEngineIDLen));
		        DEBUGMSG(("snmpusm", "\n"));

                    }
                } else {
                    fprintf(stderr, "Bad -CE option: no argument given\n");
                    exit(1);
                }
                optind++;
                break;
            }

            default:
                fprintf(stderr, "Unknown flag passed to -C: %c\n",
                        optarg[-1]);
                exit(1);
            }
        }
        break;
    }
}
int
snmp_parse_args(int argc,
                char *const *argv,
                netsnmp_session * session, const char *localOpts,
                void (*proc) (int, char *const *, int))
{
    int             arg;
    char           *cp;
    char           *Apsz = NULL;
    char           *Xpsz = NULL;
    char           *Cpsz = NULL;
    char            Opts[BUF_SIZE];

    /*
     * initialize session to default values 
     */
    snmp_sess_init(session);
    strcpy(Opts, "Y:VhHm:M:O:I:P:D:dv:r:t:c:Z:e:E:n:u:l:x:X:a:A:p:T:-:3:");
    if (localOpts)
        strcat(Opts, localOpts);

    /*
     * get the options 
     */
    DEBUGMSGTL(("snmp_parse_args", "starting: %d/%d\n", optind, argc));
    for (arg = 0; arg < argc; arg++) {
        DEBUGMSGTL(("snmp_parse_args", " arg %d = %s\n", arg, argv[arg]));
    }

    optind = 1;
    while ((arg = getopt(argc, argv, Opts)) != EOF) {
        DEBUGMSGTL(("snmp_parse_args", "handling (#%d): %c\n", optind,
                    arg));
        switch (arg) {
        case '-':
            if (strcasecmp(optarg, "help") == 0) {
                return (-1);
            }
            if (strcasecmp(optarg, "version") == 0) {
                fprintf(stderr, "NET-SNMP version: %s\n",
                        netsnmp_get_version());
                return (-2);
            }

            handle_long_opt(optarg);
            break;

        case 'V':
            fprintf(stderr, "NET-SNMP version: %s\n",
                    netsnmp_get_version());
            return (-2);

        case 'h':
            return (-1);
            break;

        case 'H':
            init_snmp("snmpapp");
            fprintf(stderr, "Configuration directives understood:\n");
            read_config_print_usage("  ");
            return (-2);

        case 'Y':
            netsnmp_config_remember(optarg);
            break;

        case 'm':
            setenv("MIBS", optarg, 1);
            break;

        case 'M':
            setenv("MIBDIRS", optarg, 1);
            break;

        case 'O':
            cp = snmp_out_toggle_options(optarg);
            if (cp != NULL) {
                fprintf(stderr,
                        "Unknown output option passed to -O: %c.\n", *cp);
                return (-1);
            }
            break;

        case 'I':
            cp = snmp_in_toggle_options(optarg);
            if (cp != NULL) {
                fprintf(stderr, "Unknown input option passed to -I: %c.\n",
                        *cp);
                return (-1);
            }
            break;

        case 'P':
            cp = snmp_mib_toggle_options(optarg);
            if (cp != NULL) {
                fprintf(stderr,
                        "Unknown parsing option passed to -P: %c.\n", *cp);
                return (-1);
            }
            break;

        case 'D':
            debug_register_tokens(optarg);
            snmp_set_do_debugging(1);
            break;

        case 'd':
            ds_set_boolean(DS_LIBRARY_ID, DS_LIB_DUMP_PACKET, 1);
            break;

        case 'v':
            if (!strcmp(optarg, "1")) {
                session->version = SNMP_VERSION_1;
            } else if (!strcasecmp(optarg, "2c")) {
                session->version = SNMP_VERSION_2c;
            } else if (!strcasecmp(optarg, "3")) {
                session->version = SNMP_VERSION_3;
            } else {
                fprintf(stderr,
                        "Invalid version specified after -v flag: %s\n",
                        optarg);
                return (-1);
            }
            break;

        case 'p':
            fprintf(stderr, "Warning: -p option is no longer used - ");
            fprintf(stderr, "specify the remote host as HOST:PORT\n");
            return (-1);
            break;

        case 'T':
            fprintf(stderr, "Warning: -T option is no longer used - ");
            fprintf(stderr, "specify the remote host as TRANSPORT:HOST\n");
            return (-1);
            break;

        case 't':
            session->timeout = atoi(optarg) * 1000000L;
            if (session->timeout < 0 || !isdigit(optarg[0])) {
                fprintf(stderr,
                        "Invalid timeout in seconds after -t flag.\n");
                return (-1);
            }
            break;

        case 'r':
            session->retries = atoi(optarg);
            if (session->retries < 0 || !isdigit(optarg[0])) {
                fprintf(stderr,
                        "Invalid number of retries after -r flag.\n");
                return (-1);
            }
            break;

        case 'c':
            Cpsz = optarg;
            break;

        case '3':
            if (snmpv3_options(optarg, session, &Apsz, &Xpsz, argc, argv) <
                0) {
                return (-1);
            }
            break;

#define SNMPV3_CMD_OPTIONS
#ifdef  SNMPV3_CMD_OPTIONS
        case 'Z':
            session->engineBoots = strtoul(optarg, NULL, 10);
            if (session->engineBoots == 0 || !isdigit(optarg[0])) {
                fprintf(stderr,
                        "Need engine boots value after -Z flag.\n");
                return (-1);
            }
            cp = strchr(optarg, ',');
            if (cp && *(++cp) && isdigit(*cp))
                session->engineTime = strtoul(cp, NULL, 10);
            /*
             * Handle previous '-Z boot time' syntax 
             */
            else if ((optind < argc) && isdigit(argv[optind][0]))
                session->engineTime = strtoul(argv[optind], NULL, 10);
            else {
                fprintf(stderr, "Need engine time value after -Z flag.\n");
                return (-1);
            }
            break;

        case 'e':{
                size_t          ebuf_len = 32, eout_len = 0;
                u_char         *ebuf = (u_char *) malloc(ebuf_len);

                if (ebuf == NULL) {
                    fprintf(stderr,
                            "malloc failure processing -e flag.\n");
                    return (-1);
                }
                if (!snmp_hex_to_binary
                    (&ebuf, &ebuf_len, &eout_len, 1, optarg)) {
                    fprintf(stderr,
                            "Bad engine ID value after -e flag.\n");
                    free(ebuf);
                    return (-1);
                }
                session->securityEngineID = ebuf;
                session->securityEngineIDLen = eout_len;
                break;
            }

        case 'E':{
                size_t          ebuf_len = 32, eout_len = 0;
                u_char         *ebuf = (u_char *) malloc(ebuf_len);

                if (ebuf == NULL) {
                    fprintf(stderr,
                            "malloc failure processing -E flag.\n");
                    return (-1);
                }
                if (!snmp_hex_to_binary
                    (&ebuf, &ebuf_len, &eout_len, 1, optarg)) {
                    fprintf(stderr,
                            "Bad engine ID value after -E flag.\n");
                    free(ebuf);
                    return (-1);
                }
                session->contextEngineID = ebuf;
                session->contextEngineIDLen = eout_len;
                break;
            }

        case 'n':
            session->contextName = optarg;
            session->contextNameLen = strlen(optarg);
            break;

        case 'u':
            session->securityName = optarg;
            session->securityNameLen = strlen(optarg);
            break;

        case 'l':
            if (!strcasecmp(optarg, "noAuthNoPriv") || !strcmp(optarg, "1")
                || !strcasecmp(optarg, "nanp")) {
                session->securityLevel = SNMP_SEC_LEVEL_NOAUTH;
            } else if (!strcasecmp(optarg, "authNoPriv")
                       || !strcmp(optarg, "2")
                       || !strcasecmp(optarg, "anp")) {
                session->securityLevel = SNMP_SEC_LEVEL_AUTHNOPRIV;
            } else if (!strcasecmp(optarg, "authPriv")
                       || !strcmp(optarg, "3")
                       || !strcasecmp(optarg, "ap")) {
                session->securityLevel = SNMP_SEC_LEVEL_AUTHPRIV;
            } else {
                fprintf(stderr,
                        "Invalid security level specified after -l flag: %s\n",
                        optarg);
                return (-1);
            }

            break;

        case 'a':
            if (!strcasecmp(optarg, "MD5")) {
                session->securityAuthProto = usmHMACMD5AuthProtocol;
                session->securityAuthProtoLen = USM_AUTH_PROTO_MD5_LEN;
            } else if (!strcasecmp(optarg, "SHA")) {
                session->securityAuthProto = usmHMACSHA1AuthProtocol;
                session->securityAuthProtoLen = USM_AUTH_PROTO_SHA_LEN;
            } else {
                fprintf(stderr,
                        "Invalid authentication protocol specified after -a flag: %s\n",
                        optarg);
                return (-1);
            }
            break;

        case 'x':
            if (!strcasecmp(optarg, "DES")) {
                session->securityPrivProto = usmDESPrivProtocol;
                session->securityPrivProtoLen = USM_PRIV_PROTO_DES_LEN;
            } else {
                fprintf(stderr,
                        "Invalid privacy protocol specified after -x flag: %s\n",
                        optarg);
                return (-1);
            }
            break;

        case 'A':
            Apsz = optarg;
            break;

        case 'X':
            Xpsz = optarg;
            break;
#endif                          /* SNMPV3_CMD_OPTIONS */

        case '?':
            return (-1);
            break;

        default:
            proc(argc, argv, arg);
            break;
        }
    }
    DEBUGMSGTL(("snmp_parse_args", "finished: %d/%d\n", optind, argc));

    /*
     * read in MIB database and initialize the snmp library
     */
    init_snmp("snmpapp");

    /*
     * session default version 
     */
    if (session->version == SNMP_DEFAULT_VERSION) {
        /*
         * run time default version 
         */
        session->version = ds_get_int(DS_LIBRARY_ID, DS_LIB_SNMPVERSION);

        /*
         * compile time default version 
         */
        if (!session->version) {
            switch (SNMP_DEFAULT_VERSION) {
            case 1:
                session->version = SNMP_VERSION_1;
                break;

            case 2:
                session->version = SNMP_VERSION_2c;
                break;

            case 3:
                session->version = SNMP_VERSION_3;
                break;
            }
        } else {
            if (session->version == DS_SNMP_VERSION_1)  /* bogus value.  version 1 actually = 0 */
                session->version = SNMP_VERSION_1;
        }
    }

    /*
     * make master key from pass phrases 
     */
    if (Apsz) {
        session->securityAuthKeyLen = USM_AUTH_KU_LEN;
        if (session->securityAuthProto == NULL) {
            /*
             * get .conf set default 
             */
            const oid      *def =
                get_default_authtype(&session->securityAuthProtoLen);
            session->securityAuthProto =
                snmp_duplicate_objid(def, session->securityAuthProtoLen);
        }
        if (session->securityAuthProto == NULL) {
            /*
             * assume MD5 
             */
            session->securityAuthProto =
                snmp_duplicate_objid(usmHMACMD5AuthProtocol,
                                     USM_AUTH_PROTO_MD5_LEN);
            session->securityAuthProtoLen = USM_AUTH_PROTO_MD5_LEN;
        }
        if (generate_Ku(session->securityAuthProto,
                        session->securityAuthProtoLen,
                        (u_char *) Apsz, strlen(Apsz),
                        session->securityAuthKey,
                        &session->securityAuthKeyLen) != SNMPERR_SUCCESS) {
            snmp_perror(argv[0]);
            fprintf(stderr,
                    "Error generating a key (Ku) from the supplied authentication pass phrase. \n");
            return (-2);
        }
    }
    if (Xpsz) {
        session->securityPrivKeyLen = USM_PRIV_KU_LEN;
        if (session->securityPrivProto == NULL) {
            /*
             * get .conf set default 
             */
            const oid      *def =
                get_default_privtype(&session->securityPrivProtoLen);
            session->securityPrivProto =
                snmp_duplicate_objid(def, session->securityPrivProtoLen);
        }
        if (session->securityPrivProto == NULL) {
            /*
             * assume DES 
             */
            session->securityPrivProto =
                snmp_duplicate_objid(usmDESPrivProtocol,
                                     USM_PRIV_PROTO_DES_LEN);
            session->securityPrivProtoLen = USM_PRIV_PROTO_DES_LEN;
        }
        if (generate_Ku(session->securityAuthProto,
                        session->securityAuthProtoLen,
                        (u_char *) Xpsz, strlen(Xpsz),
                        session->securityPrivKey,
                        &session->securityPrivKeyLen) != SNMPERR_SUCCESS) {
            snmp_perror(argv[0]);
            fprintf(stderr,
                    "Error generating a key (Ku) from the supplied privacy pass phrase. \n");
            return (-2);
        }
    }
    /*
     * get the hostname 
     */
    if (optind == argc) {
        fprintf(stderr, "No hostname specified.\n");
        return (-1);
    }
    session->peername = argv[optind++]; /* hostname */

    /*
     * If v1 or v2c, check community has been set, either by a -c option above,
     * or via a default token somewhere.  
     */

    if (session->version == SNMP_VERSION_1 ||
        session->version == SNMP_VERSION_2c) {
        if (Cpsz == NULL) {
            Cpsz = ds_get_string(DS_LIBRARY_ID, DS_LIB_COMMUNITY);
        }
        if (Cpsz == NULL) {
            fprintf(stderr, "No community name specified.\n");
            return (-1);
        }
        session->community = (unsigned char *) Cpsz;
        session->community_len = strlen(Cpsz);
    }
    return optind;
}