2 * snmpusm.c - send snmp SET requests to a network entity to change the
5 * XXX get engineID dynamicly.
6 * XXX read passwords from prompts
7 * XXX customize responses with user names, etc.
9 #include <net-snmp/net-snmp-config.h>
22 #include <sys/types.h>
24 #include <netinet/in.h>
28 #if TIME_WITH_SYS_TIME
30 # include <sys/timeb.h>
32 # include <sys/time.h>
37 # include <sys/time.h>
43 #include <sys/select.h>
52 #include <arpa/inet.h>
55 #include <net-snmp/net-snmp-includes.h>
57 int main(int, char **);
59 #define CMD_PASSWD_NAME "passwd"
61 #define CMD_CREATE_NAME "create"
63 #define CMD_DELETE_NAME "delete"
65 #define CMD_CLONEFROM_NAME "cloneFrom"
66 #define CMD_CLONEFROM 4
70 static const char *successNotes[CMD_NUM] = {
71 "SNMPv3 Key(s) successfully changed.",
72 "User successfully created.",
73 "User successfully deleted.",
74 "User successfully cloned."
77 #define USM_OID_LEN 12
79 static oid authKeyOid[MAX_OID_LEN] =
80 { 1, 3, 6, 1, 6, 3, 15, 1, 2, 2, 1, 6 }, ownAuthKeyOid[MAX_OID_LEN] = {
81 1, 3, 6, 1, 6, 3, 15, 1, 2, 2, 1, 7}, privKeyOid[MAX_OID_LEN] = {
82 1, 3, 6, 1, 6, 3, 15, 1, 2, 2, 1, 9}, ownPrivKeyOid[MAX_OID_LEN] = {
83 1, 3, 6, 1, 6, 3, 15, 1, 2, 2, 1, 10}, usmUserCloneFrom[MAX_OID_LEN] = {
84 1, 3, 6, 1, 6, 3, 15, 1, 2, 2, 1, 4}, usmUserSecurityName[MAX_OID_LEN] = {
85 1, 3, 6, 1, 6, 3, 15, 1, 2, 2, 1, 3}, usmUserStatus[MAX_OID_LEN] = {
86 1, 3, 6, 1, 6, 3, 15, 1, 2, 2, 1, 13}
91 oid *authKeyChange = authKeyOid, *privKeyChange = privKeyOid;
92 int doauthkey = 0, doprivkey = 0;
97 fprintf(stderr, "Usage: snmpusm ");
98 snmp_parse_args_usage(stderr);
99 fprintf(stderr, " COMMAND\n\n");
100 snmp_parse_args_descriptions(stderr);
101 fprintf(stderr, "\nsnmpusm commands:\n");
102 fprintf(stderr, " create USER [CLONEFROM-USER]\n");
103 fprintf(stderr, " delete USER\n");
104 fprintf(stderr, " cloneFrom USER CLONEFROM-USER\n");
106 " passwd [-Co] [-Ca] [-Cx] OLD-PASSPHRASE NEW-PASSPHRASE\n");
107 fprintf(stderr, "\t\t-Co\t\tUse the ownKeyChange objects.\n");
108 fprintf(stderr, "\t\t-Cx\t\tChange the privacy key.\n");
109 fprintf(stderr, "\t\t-Ca\t\tChange the authentication key.\n");
113 * setup_oid appends to the oid the index for the engineid/user
116 setup_oid(oid * it, size_t * len, u_char * id, size_t idlen,
121 *len = itIndex + 1 + idlen + 1 + strlen(user);
123 it[itIndex++] = idlen;
124 for (i = 0; i < (int) idlen; i++) {
125 it[itIndex++] = id[i];
128 it[itIndex++] = strlen(user);
129 for (i = 0; i < (int) strlen(user); i++) {
130 it[itIndex++] = user[i];
134 * fprintf(stdout, "setup_oid: ");
137 * fprint_objid(stdout, it, *len);
140 * fprintf(stdout, "\n");
145 optProc(int argc, char *const *argv, int opt)
152 authKeyChange = ownAuthKeyOid;
153 privKeyChange = ownPrivKeyOid;
165 fprintf(stderr, "Unknown flag passed to -C: %c\n",
175 main(int argc, char *argv[])
177 netsnmp_session session, *ss;
178 netsnmp_pdu *pdu = NULL, *response = NULL;
180 netsnmp_variable_list *vars;
186 int current_name = 0;
187 int current_type = 0;
188 int current_value = 0;
192 oid name[MAX_OID_LEN];
194 size_t name_length = USM_OID_LEN;
195 size_t name_length2 = USM_OID_LEN;
202 size_t oldKu_len = SNMP_MAXBUF_SMALL,
203 newKu_len = SNMP_MAXBUF_SMALL,
204 oldkul_len = SNMP_MAXBUF_SMALL,
205 newkul_len = SNMP_MAXBUF_SMALL, keychange_len = SNMP_MAXBUF_SMALL;
207 char *newpass = NULL, *oldpass = NULL;
208 u_char oldKu[SNMP_MAXBUF_SMALL],
209 newKu[SNMP_MAXBUF_SMALL],
210 oldkul[SNMP_MAXBUF_SMALL],
211 newkul[SNMP_MAXBUF_SMALL], keychange[SNMP_MAXBUF_SMALL];
213 authKeyChange = authKeyOid;
214 privKeyChange = privKeyOid;
217 * get the common command line arguments
219 switch (arg = snmp_parse_args(argc, argv, &session, "C:", optProc)) {
232 * open an SNMP session
235 * Note: this wil obtain the engineID needed below
237 ss = snmp_open(&session);
240 * diagnose snmp_open errors with the input netsnmp_session pointer
242 snmp_sess_perror("snmpusm", &session);
247 * create PDU for SET request and add object names and values to request
249 pdu = snmp_pdu_create(SNMP_MSG_SET);
252 fprintf(stderr, "Please specify a opreation to perform.\n");
257 if (strcmp(argv[arg], CMD_PASSWD_NAME) == 0) {
260 * passwd: change a users password.
262 * XXX: Uses the auth type of the calling user, a MD5 user can't
263 * change a SHA user's key.
265 command = CMD_PASSWD;
266 oldpass = argv[++arg];
267 newpass = argv[++arg];
269 if (doprivkey == 0 && doauthkey == 0)
270 doprivkey = doauthkey = 1;
272 if (newpass == NULL || strlen(newpass) < USM_LENGTH_P_MIN) {
274 "New passphrase must be greater than %d characters in length.\n",
279 if (oldpass == NULL || strlen(oldpass) < USM_LENGTH_P_MIN) {
281 "Old passphrase must be greater than %d characters in length.\n",
287 * do we have a securityName? If not, copy the default
289 if (session.securityName == NULL) {
290 session.securityName =
291 strdup(netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
292 NETSNMP_DS_LIB_SECNAME));
296 * the old Ku is in the session, but we need the new one
298 if (session.securityAuthProto == NULL) {
300 * get .conf set default
303 get_default_authtype(&session.securityAuthProtoLen);
304 session.securityAuthProto =
305 snmp_duplicate_objid(def, session.securityAuthProtoLen);
307 if (session.securityAuthProto == NULL) {
311 session.securityAuthProtoLen =
312 sizeof(usmHMACMD5AuthProtocol) / sizeof(oid);
313 session.securityAuthProto =
314 snmp_duplicate_objid(usmHMACMD5AuthProtocol,
315 session.securityAuthProtoLen);
317 rval = generate_Ku(session.securityAuthProto,
318 session.securityAuthProtoLen,
319 (u_char *) newpass, strlen(newpass),
322 if (rval != SNMPERR_SUCCESS) {
323 snmp_perror(argv[0]);
324 fprintf(stderr, "generating the old Ku failed\n");
329 * the old Ku is in the session, but we need the new one
331 rval = generate_Ku(session.securityAuthProto,
332 session.securityAuthProtoLen,
333 (u_char *) oldpass, strlen(oldpass),
336 if (rval != SNMPERR_SUCCESS) {
337 snmp_perror(argv[0]);
338 fprintf(stderr, "generating the new Ku failed\n");
343 * generate the two Kul's
345 rval = generate_kul(session.securityAuthProto,
346 session.securityAuthProtoLen,
347 ss->contextEngineID, ss->contextEngineIDLen,
348 oldKu, oldKu_len, oldkul, &oldkul_len);
350 if (rval != SNMPERR_SUCCESS) {
351 snmp_perror(argv[0]);
352 fprintf(stderr, "generating the old Kul failed\n");
356 rval = generate_kul(session.securityAuthProto,
357 session.securityAuthProtoLen,
358 ss->contextEngineID, ss->contextEngineIDLen,
359 newKu, newKu_len, newkul, &newkul_len);
361 if (rval != SNMPERR_SUCCESS) {
362 snmp_perror(argv[0]);
363 fprintf(stderr, "generating the new Kul failed\n");
368 * create the keychange string
370 rval = encode_keychange(session.securityAuthProto,
371 session.securityAuthProtoLen,
374 keychange, &keychange_len);
376 if (rval != SNMPERR_SUCCESS) {
377 snmp_perror(argv[0]);
378 fprintf(stderr, "encoding the keychange failed\n");
384 * add the keychange string to the outgoing packet
387 setup_oid(authKeyChange, &name_length,
388 ss->contextEngineID, ss->contextEngineIDLen,
389 session.securityName);
390 snmp_pdu_add_variable(pdu, authKeyChange, name_length,
391 ASN_OCTET_STR, keychange, keychange_len);
394 setup_oid(privKeyChange, &name_length,
395 ss->contextEngineID, ss->contextEngineIDLen,
396 session.securityName);
397 snmp_pdu_add_variable(pdu, privKeyChange, name_length,
398 ASN_OCTET_STR, keychange, keychange_len);
401 } else if (strcmp(argv[arg], CMD_CREATE_NAME) == 0) {
403 * create: create a user
405 * create USER [CLONEFROM]
408 fprintf(stderr, "You must specify the user name to create\n");
413 command = CMD_CREATE;
414 setup_oid(usmUserStatus, &name_length,
415 ss->contextEngineID, ss->contextEngineIDLen, argv[arg]);
416 longvar = RS_CREATEANDGO;
417 snmp_pdu_add_variable(pdu, usmUserStatus, name_length,
418 ASN_INTEGER, (u_char *) & longvar,
423 * clone the new user from another user as well
425 setup_oid(usmUserCloneFrom, &name_length,
426 ss->contextEngineID, ss->contextEngineIDLen,
428 setup_oid(usmUserSecurityName, &name_length2,
429 ss->contextEngineID, ss->contextEngineIDLen,
431 snmp_pdu_add_variable(pdu, usmUserCloneFrom, name_length,
433 (u_char *) usmUserSecurityName,
434 sizeof(oid) * name_length2);
437 } else if (strcmp(argv[arg], CMD_CLONEFROM_NAME) == 0) {
439 * create: clone a user from another
441 * cloneFrom USER FROM
445 "You must specify the user name to operate on\n");
450 command = CMD_CLONEFROM;
451 setup_oid(usmUserCloneFrom, &name_length,
452 ss->contextEngineID, ss->contextEngineIDLen, argv[arg]);
456 "You must specify the user name to clone from\n");
461 setup_oid(usmUserSecurityName, &name_length2,
462 ss->contextEngineID, ss->contextEngineIDLen, argv[arg]);
463 snmp_pdu_add_variable(pdu, usmUserCloneFrom, name_length,
465 (u_char *) usmUserSecurityName,
466 sizeof(oid) * name_length2);
468 } else if (strcmp(argv[arg], CMD_DELETE_NAME) == 0) {
470 * delete: delete a user
475 fprintf(stderr, "You must specify the user name to delete\n");
479 command = CMD_DELETE;
480 setup_oid(usmUserStatus, &name_length,
481 ss->contextEngineID, ss->contextEngineIDLen, argv[arg]);
482 longvar = RS_DESTROY;
483 snmp_pdu_add_variable(pdu, usmUserStatus, name_length,
484 ASN_INTEGER, (u_char *) & longvar,
487 fprintf(stderr, "Unknown command\n");
496 status = snmp_synch_response(ss, pdu, &response);
497 if (status == STAT_SUCCESS) {
499 if (response->errstat == SNMP_ERR_NOERROR) {
500 fprintf(stderr, "%s\n", successNotes[command - 1]);
502 fprintf(stderr, "Error in packet.\nReason: %s\n",
503 snmp_errstring(response->errstat));
504 if (response->errindex != 0) {
506 netsnmp_variable_list *vars;
507 fprintf(stderr, "Failed object: ");
508 for (count = 1, vars = response->variables;
509 vars && count != response->errindex;
510 vars = vars->next_variable, count++)
513 fprint_objid(stderr, vars->name,
515 fprintf(stderr, "\n");
520 } else if (status == STAT_TIMEOUT) {
521 fprintf(stderr, "Timeout: No Response from %s\n",
524 } else { /* status == STAT_ERROR */
525 snmp_sess_perror("snmpset", ss);
530 snmp_free_pdu(response);