diff options
Diffstat (limited to 'apps/snmpusm.c')
-rw-r--r-- | apps/snmpusm.c | 1023 |
1 files changed, 1023 insertions, 0 deletions
diff --git a/apps/snmpusm.c b/apps/snmpusm.c new file mode 100644 index 0000000..42919bd --- /dev/null +++ b/apps/snmpusm.c @@ -0,0 +1,1023 @@ +/* + * snmpusm.c - send snmp SET requests to a network entity to change the + * usm user database + * + * XXX get engineID dynamically. + * XXX read passwords from prompts + * XXX customize responses with user names, etc. + */ +/* Portions of this file are subject to the following copyright(s). See + * the Net-SNMP's COPYING file for more details and other copyrights + * that may apply: + */ +/* + * Portions of this file are copyrighted by: + * Copyright © 2003 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms specified in the COPYING file + * distributed with the Net-SNMP package. + */ +#include <net-snmp/net-snmp-config.h> + +#if HAVE_STDLIB_H +#include <stdlib.h> +#endif +#if HAVE_UNISTD_H +#include <unistd.h> +#endif +#if HAVE_STRING_H +#include <string.h> +#else +#include <strings.h> +#endif +#include <sys/types.h> +#if HAVE_NETINET_IN_H +#include <netinet/in.h> +#endif +#include <stdio.h> +#include <ctype.h> +#if TIME_WITH_SYS_TIME +# include <sys/time.h> +# include <time.h> +#else +# if HAVE_SYS_TIME_H +# include <sys/time.h> +# else +# include <time.h> +# endif +#endif +#if HAVE_SYS_SELECT_H +#include <sys/select.h> +#endif +#if HAVE_NETDB_H +#include <netdb.h> +#endif +#if HAVE_ARPA_INET_H +#include <arpa/inet.h> +#endif + +#if defined(HAVE_OPENSSL_DH_H) && defined(HAVE_LIBCRYPTO) +#include <openssl/dh.h> +#endif /* HAVE_OPENSSL_DH_H && HAVE_LIBCRYPTO */ + +#include <net-snmp/net-snmp-includes.h> + +int main(int, char **); + +#define CMD_PASSWD_NAME "passwd" +#define CMD_PASSWD 1 +#define CMD_CREATE_NAME "create" +#define CMD_CREATE 2 +#define CMD_DELETE_NAME "delete" +#define CMD_DELETE 3 +#define CMD_CLONEFROM_NAME "cloneFrom" +#define CMD_CLONEFROM 4 +#define CMD_ACTIVATE_NAME "activate" +#define CMD_ACTIVATE 5 +#define CMD_DEACTIVATE_NAME "deactivate" +#define CMD_DEACTIVATE 6 +#define CMD_CHANGEKEY_NAME "changekey" +#define CMD_CHANGEKEY 7 + +#define CMD_NUM 7 + +static const char *successNotes[CMD_NUM] = { + "SNMPv3 Key(s) successfully changed.", + "User successfully created.", + "User successfully deleted.", + "User successfully cloned.", + "User successfully activated.", + "User successfully deactivated.", + "SNMPv3 Key(s) successfully changed." +}; + +#define USM_OID_LEN 12 +#define DH_USM_OID_LEN 11 + +static oid + +authKeyOid[MAX_OID_LEN] = { 1, 3, 6, 1, 6, 3, 15, 1, 2, 2, 1, 6 }, +ownAuthKeyOid[MAX_OID_LEN] = {1, 3, 6, 1, 6, 3, 15, 1, 2, 2, 1, 7}, +privKeyOid[MAX_OID_LEN] = {1, 3, 6, 1, 6, 3, 15, 1, 2, 2, 1, 9}, +ownPrivKeyOid[MAX_OID_LEN] = {1, 3, 6, 1, 6, 3, 15, 1, 2, 2, 1, 10}, +usmUserCloneFrom[MAX_OID_LEN] = {1, 3, 6, 1, 6, 3, 15, 1, 2, 2, 1, 4}, +usmUserSecurityName[MAX_OID_LEN] = {1, 3, 6, 1, 6, 3, 15, 1, 2, 2, 1, 3}, +usmUserPublic[MAX_OID_LEN] = {1, 3, 6, 1, 6, 3, 15, 1, 2, 2, 1, 11}, +usmUserStatus[MAX_OID_LEN] = {1, 3, 6, 1, 6, 3, 15, 1, 2, 2, 1, 13}, +/* diffie helman change key objects */ +usmDHUserAuthKeyChange[MAX_OID_LEN] = {1, 3, 6, 1, 3, 101, 1, 1, 2, 1, 1 }, +usmDHUserPrivKeyChange[MAX_OID_LEN] = {1, 3, 6, 1, 3, 101, 1, 1, 2, 1, 3 }, +#if defined(HAVE_OPENSSL_DH_H) && defined(HAVE_LIBCRYPTO) +usmDHUserOwnAuthKeyChange[MAX_OID_LEN] = {1, 3, 6, 1, 3, 101, 1, 1, 2, 1, 2 }, +usmDHUserOwnPrivKeyChange[MAX_OID_LEN] = {1, 3, 6, 1, 3, 101, 1, 1, 2, 1, 4 }, +#endif /* HAVE_OPENSSL_DH_H && HAVE_LIBCRYPTO */ +usmDHParameters[] = { 1,3,6,1,3,101,1,1,1,0 } +; +size_t usmDHParameters_len = OID_LENGTH(usmDHParameters); + +static +oid *authKeyChange = authKeyOid, *privKeyChange = privKeyOid; +oid *dhauthKeyChange = usmDHUserAuthKeyChange, + *dhprivKeyChange = usmDHUserPrivKeyChange; +int doauthkey = 0, doprivkey = 0, uselocalizedkey = 0; +size_t usmUserEngineIDLen = 0; +u_char *usmUserEngineID = NULL; +char *usmUserPublic_val = NULL; +int docreateandwait = 0; + + +void +usage(void) +{ + fprintf(stderr, "Usage: snmpusm "); + snmp_parse_args_usage(stderr); + fprintf(stderr, " COMMAND\n\n"); + snmp_parse_args_descriptions(stderr); + fprintf(stderr, "\nsnmpusm commands:\n"); + fprintf(stderr, " [options] create USER [CLONEFROM-USER]\n"); + fprintf(stderr, " [options] delete USER\n"); + fprintf(stderr, " [options] activate USER\n"); + fprintf(stderr, " [options] deactivate USER\n"); + fprintf(stderr, " [options] [-Cw] cloneFrom USER CLONEFROM-USER\n"); + fprintf(stderr, " [options] [-Ca] [-Cx] changekey [USER]\n"); + fprintf(stderr, + " [options] [-Ca] [-Cx] passwd OLD-PASSPHRASE NEW-PASSPHRASE [USER]\n"); + fprintf(stderr, + " [options] (-Ca|-Cx) -Ck passwd OLD-KEY-OR-PASS NEW-KEY-OR-PASS [USER]\n"); + fprintf(stderr, "\nsnmpusm options:\n"); + fprintf(stderr, "\t-CE ENGINE-ID\tSet usmUserEngineID (e.g. 800000020109840301).\n"); + fprintf(stderr, "\t-Cp STRING\tSet usmUserPublic value to STRING.\n"); + fprintf(stderr, "\t-Cw\t\tCreate the user with createAndWait.\n"); + fprintf(stderr, "\t\t\t(it won't be active until you active it)\n"); + fprintf(stderr, "\t-Cx\t\tChange the privacy key.\n"); + fprintf(stderr, "\t-Ca\t\tChange the authentication key.\n"); + fprintf(stderr, "\t-Ck\t\tAllows to use localized key (must start with 0x)\n"); + fprintf(stderr, "\t\t\tinstead of passphrase.\n"); +} + +/* + * setup_oid appends to the oid the index for the engineid/user + */ +void +setup_oid(oid * it, size_t * len, u_char * id, size_t idlen, + const char *user) +{ + int i, itIndex = *len; + + *len = itIndex + 1 + idlen + 1 + strlen(user); + + it[itIndex++] = idlen; + for (i = 0; i < (int) idlen; i++) { + it[itIndex++] = id[i]; + } + + it[itIndex++] = strlen(user); + for (i = 0; i < (int) strlen(user); i++) { + it[itIndex++] = user[i]; + } + +#ifdef NETSNMP_ENABLE_TESTING_CODE + fprintf(stdout, "setup_oid: "); + fprint_objid(stdout, it, *len); + fprintf(stdout, "\n"); +#endif +} + +#if defined(HAVE_OPENSSL_DH_H) && defined(HAVE_LIBCRYPTO) +int +get_USM_DH_key(netsnmp_variable_list *vars, netsnmp_variable_list *dhvar, + size_t outkey_len, + netsnmp_pdu *pdu, const char *keyname, + oid *keyoid, size_t keyoid_len) { + u_char *dhkeychange; + DH *dh; + BIGNUM *other_pub; + u_char *key; + size_t key_len; + + dhkeychange = (u_char *) malloc(2 * vars->val_len * sizeof(char)); + if (!dhkeychange) + return SNMPERR_GENERR; + + memcpy(dhkeychange, vars->val.string, vars->val_len); + + { + const unsigned char *cp = dhvar->val.string; + dh = d2i_DHparams(NULL, &cp, dhvar->val_len); + } + + if (!dh || !dh->g || !dh->p) { + SNMP_FREE(dhkeychange); + return SNMPERR_GENERR; + } + + DH_generate_key(dh); + if (!dh->pub_key) { + SNMP_FREE(dhkeychange); + return SNMPERR_GENERR; + } + + if (vars->val_len != (unsigned int)BN_num_bytes(dh->pub_key)) { + SNMP_FREE(dhkeychange); + fprintf(stderr,"incorrect diffie-helman lengths (%lu != %d)\n", + (unsigned long)vars->val_len, BN_num_bytes(dh->pub_key)); + return SNMPERR_GENERR; + } + + BN_bn2bin(dh->pub_key, dhkeychange + vars->val_len); + + key_len = DH_size(dh); + if (!key_len) { + SNMP_FREE(dhkeychange); + return SNMPERR_GENERR; + } + key = (u_char *) malloc(key_len * sizeof(u_char)); + + if (!key) { + SNMP_FREE(dhkeychange); + return SNMPERR_GENERR; + } + + other_pub = BN_bin2bn(vars->val.string, vars->val_len, NULL); + if (!other_pub) { + SNMP_FREE(dhkeychange); + SNMP_FREE(key); + return SNMPERR_GENERR; + } + + if (DH_compute_key(key, other_pub, dh)) { + u_char *kp; + + printf("new %s key: 0x", keyname); + for(kp = key + key_len - outkey_len; + kp - key < (int)key_len; kp++) { + printf("%02x", (unsigned char) *kp); + } + printf("\n"); + } + + snmp_pdu_add_variable(pdu, keyoid, keyoid_len, + ASN_OCTET_STR, dhkeychange, + 2 * vars->val_len); + + SNMP_FREE(dhkeychange); + SNMP_FREE(other_pub); + SNMP_FREE(key); + + return SNMPERR_SUCCESS; +} +#endif /* HAVE_OPENSSL_DH_H */ + +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 'w': + docreateandwait = 1; + break; + + case 'E': { + size_t ebuf_len = 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 +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 NETSNMP_PARSE_ARGS_ERROR: + exit(1); + case NETSNMP_PARSE_ARGS_SUCCESS_EXIT: + exit(0); + case NETSNMP_PARSE_ARGS_ERROR_USAGE: + 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]); + 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(); + 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 && HAVE_LIBCRYPTO */ + } 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; + } + +#if defined(HAVE_OPENSSL_DH_H) && defined(HAVE_LIBCRYPTO) + begone: +#endif /* HAVE_OPENSSL_DH_H && HAVE_LIBCRYPTO */ + if (response) + snmp_free_pdu(response); + snmp_close(ss); + SOCK_CLEANUP; + return exitval; +} |