Beispiel #1
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 = 1;
    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];

    SOCK_STARTUP;

    authKeyChange = authKeyOid;
    privKeyChange = privKeyOid;

    /*
     * get the common command line arguments 
     */
    switch (arg = snmp_parse_args(argc, argv, &session, "C:", optProc)) {
    case NETSNMP_PARSE_ARGS_ERROR:
        goto out;
    case NETSNMP_PARSE_ARGS_SUCCESS_EXIT:
        exitval = 0;
        goto out;
    case NETSNMP_PARSE_ARGS_ERROR_USAGE:
        usage();
        goto out;
    default:
        break;
    }

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

    /*
     * 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);
        goto out;
    }

    /*
     * 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");
        goto close_session;
    }


    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);
            goto close_session;
        }

        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);
            goto close_session;
        }

        DEBUGMSGTL(("9:usm:passwd", "oldpass len %" NETSNMP_PRIz "d, newpass len %" NETSNMP_PRIz "d\n",
                    strlen(oldpass), strlen(newpass)));

        /* 
         * 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");
	      goto close_session;
	    }
	    
	    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");
	        goto close_session;
	    }

	    /*
	     * 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");
		goto close_session;
	    }
            DEBUGMSGTL(("9:usm:passwd", "oldkul len %" NETSNMP_PRIz "d\n", oldkul_len));
	}
	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");
	      goto close_session;
	    }
	    
	    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");
                goto close_session;
            }

	    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");
		goto close_session;
	    }
            DEBUGMSGTL(("9:usm:passwd", "newkul len %" NETSNMP_PRIz "d\n", newkul_len));
	}

        /*
         * 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) {
            int privtype, properlength;
            u_char *okp = oldkulpriv, *nkp = newkulpriv;
            if (!session.securityPrivProto) {
                snmp_log(LOG_ERR, "no encryption type specified, which I need in order to know to change the key\n");
                goto close_session;
            }

            privtype = sc_get_privtype(session.securityPrivProto,
                                       session.securityPrivProtoLen);
            properlength = sc_get_proper_priv_length_bytype(privtype);
            if (USM_CREATE_USER_PRIV_DES == privtype)
                properlength *= 2; /* ?? we store salt with key */
            DEBUGMSGTL(("9:usm:passwd", "proper len %d\n", properlength));
            oldkulpriv_len = oldkul_len;
            newkulpriv_len = newkul_len;
            memcpy(oldkulpriv, oldkul, oldkulpriv_len);
            memcpy(newkulpriv, newkul, newkulpriv_len);

            if (oldkulpriv_len > properlength) {
                oldkulpriv_len = newkulpriv_len = properlength;
            }
            else if (oldkulpriv_len < properlength) {
                rval = netsnmp_extend_kul(properlength,
                                          session.securityAuthProto,
                                          session.securityAuthProtoLen,
                                          privtype,
                                          usmUserEngineID, usmUserEngineIDLen,
                                          &okp, &oldkulpriv_len,
                                          sizeof(oldkulpriv));
                rval = netsnmp_extend_kul(properlength,
                                          session.securityAuthProto,
                                          session.securityAuthProtoLen,
                                          privtype,
                                          usmUserEngineID, usmUserEngineIDLen,
                                          &nkp, &newkulpriv_len,
                                          sizeof(newkulpriv));
            }
        }

        /*
         * 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();
            goto close_session;
	  }
	}

        /* which is slightly different for encryption if lengths are
           different */
	if (doprivkey) {
            DEBUGMSGTL(("9:usm:passwd:encode", "proper len %" NETSNMP_PRIz "d, old_len %" NETSNMP_PRIz "d, new_len %" NETSNMP_PRIz "d\n",
                        oldkulpriv_len, oldkulpriv_len, newkulpriv_len));
	  rval = encode_keychange(session.securityAuthProto,
                                session.securityAuthProtoLen,
                                oldkulpriv, oldkulpriv_len,
                                newkulpriv, newkulpriv_len,
                                keychangepriv, &keychangepriv_len);

          DEBUGMSGTL(("9:usm:passwd:encode", "keychange len %" NETSNMP_PRIz "d\n",
                      keychangepriv_len));
	  if (rval != SNMPERR_SUCCESS) {
            snmp_perror(argv[0]);
            fprintf(stderr, "encoding the keychange failed\n");
            usage();
            goto close_session;
	  }
	}

        /*
         * 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();
            goto close_session;
        }

        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]);
            if (docreateandwait) {
                longvar = RS_CREATEANDWAIT;
            } else {
                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();
            goto close_session;
        }

        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();
            goto close_session;
        }

        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");
            goto close_session;
        }

        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");
            goto close_session;
        }

        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");
            goto close_session;
        }

        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");
            goto close_session;
        }

        /* 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;
            int privtype = sc_get_privtype(ss->securityPrivProto,
                                           ss->securityPrivProtoLen);
            dhprivKeyLen = sc_get_proper_priv_length_bytype(privtype);
            if (USM_CREATE_USER_PRIV_DES == privtype)
                dhprivKeyLen *= 2; /* ?? we store salt with key */
            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 && HAVE_LIBCRYPTO */
    } else {
        fprintf(stderr, "Unknown command\n");
        usage();
        goto close_session;
    }

    /*
     * 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;
    }

    exitval = 0;
#if defined(HAVE_OPENSSL_DH_H) && defined(HAVE_LIBCRYPTO)
  begone:
#endif /* HAVE_OPENSSL_DH_H && HAVE_LIBCRYPTO */
    if (response)
        snmp_free_pdu(response);

close_session:
    snmp_close(ss);

out:
    SOCK_CLEANUP;
    return exitval;
}
Beispiel #2
0
int
main(int argc, char *argv[])
{
    netsnmp_session session, *ss;
    netsnmp_pdu    *pdu = NULL, *response = NULL;
#ifdef notused
    netsnmp_variable_list *vars;
#endif

    int             arg;
#ifdef notused
    int             count;
    int             current_name = 0;
    int             current_type = 0;
    int             current_value = 0;
    char           *names[128];
    char            types[128];
    char           *values[128];
    oid             name[MAX_OID_LEN];
#endif
    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,
        newkul_len = SNMP_MAXBUF_SMALL, keychange_len = SNMP_MAXBUF_SMALL;

    char           *newpass = NULL, *oldpass = NULL;
    u_char          oldKu[SNMP_MAXBUF_SMALL],
        newKu[SNMP_MAXBUF_SMALL],
        oldkul[SNMP_MAXBUF_SMALL],
        newkul[SNMP_MAXBUF_SMALL], keychange[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;
    }

    SOCK_STARTUP;

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

    /*
     * create PDU for SET request and add object names and values to request 
     */
    pdu = snmp_pdu_create(SNMP_MSG_SET);

    if (arg >= argc) {
        fprintf(stderr, "Please specify a operation to perform.\n");
        usage();
        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.
         */
        command = CMD_PASSWD;
        oldpass = argv[++arg];
        newpass = 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);
        }

        /*
         * 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 
             */
            session.securityAuthProtoLen =
                sizeof(usmHMACMD5AuthProtocol) / sizeof(oid);
            session.securityAuthProto =
                snmp_duplicate_objid(usmHMACMD5AuthProtocol,
                                     session.securityAuthProtoLen);
        }
        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 old Ku failed\n");
            exit(1);
        }

        /*
         * 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 new Ku failed\n");
            exit(1);
        }

        /*
         * generate the two Kul's 
         */
        rval = generate_kul(session.securityAuthProto,
                            session.securityAuthProtoLen,
                            ss->contextEngineID, ss->contextEngineIDLen,
                            oldKu, oldKu_len, oldkul, &oldkul_len);

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

        rval = generate_kul(session.securityAuthProto,
                            session.securityAuthProtoLen,
                            ss->contextEngineID, ss->contextEngineIDLen,
                            newKu, newKu_len, newkul, &newkul_len);

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

        /*
         * create the keychange string 
         */
        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);
        }

        /*
         * add the keychange string to the outgoing packet 
         */
        if (doauthkey) {
            setup_oid(authKeyChange, &name_length,
                      ss->contextEngineID, ss->contextEngineIDLen,
                      session.securityName);
            snmp_pdu_add_variable(pdu, authKeyChange, name_length,
                                  ASN_OCTET_STR, keychange, keychange_len);
        }
        if (doprivkey) {
            setup_oid(privKeyChange, &name_length,
                      ss->contextEngineID, ss->contextEngineIDLen,
                      session.securityName);
            snmp_pdu_add_variable(pdu, privKeyChange, name_length,
                                  ASN_OCTET_STR, keychange, keychange_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,
                      ss->contextEngineID, ss->contextEngineIDLen, argv[arg-1]);
            longvar = RS_CREATEANDGO;
            snmp_pdu_add_variable(pdu, usmUserStatus, name_length,
                                  ASN_INTEGER, (u_char *) & longvar,
                                  sizeof(longvar));

            setup_oid(usmUserCloneFrom, &name_length,
                      ss->contextEngineID, ss->contextEngineIDLen,
                      argv[arg - 1]);
            setup_oid(usmUserSecurityName, &name_length2,
                      ss->contextEngineID, ss->contextEngineIDLen,
                      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,
                      ss->contextEngineID, ss->contextEngineIDLen, 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,
                  ss->contextEngineID, ss->contextEngineIDLen, argv[arg]);
        longvar = RS_ACTIVE;
        snmp_pdu_add_variable(pdu, usmUserStatus, name_length,
                              ASN_INTEGER, (u_char *) & longvar,
                              sizeof(longvar));
        setup_oid(usmUserCloneFrom, &name_length,
                  ss->contextEngineID, ss->contextEngineIDLen, 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,
                  ss->contextEngineID, ss->contextEngineIDLen, 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,
                  ss->contextEngineID, ss->contextEngineIDLen, argv[arg]);
        longvar = RS_DESTROY;
        snmp_pdu_add_variable(pdu, usmUserStatus, name_length,
                              ASN_INTEGER, (u_char *) & longvar,
                              sizeof(longvar));
    } else {
        fprintf(stderr, "Unknown command\n");
        usage();
        exit(1);
    }


    /*
     * do the request 
     */
    status = snmp_synch_response(ss, pdu, &response);
    if (status == STAT_SUCCESS) {
        if (response) {
            if (response->errstat == SNMP_ERR_NOERROR) {
                fprintf(stderr, "%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;
    }

    if (response)
        snmp_free_pdu(response);
    snmp_close(ss);
    SOCK_CLEANUP;
    return exitval;
}