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
);