NGINX: Upstream update to version 1.4.4
[tomato.git] / release / src / router / snmp / apps / snmpusm.c
blob38d074eba3787a09160c45021aa6b1d41030df49
1 /*
2 * snmpusm.c - send snmp SET requests to a network entity to change the
3 * usm user database
5 * XXX get engineID dynamicly.
6 * XXX read passwords from prompts
7 * XXX customize responses with user names, etc.
8 */
9 #include <net-snmp/net-snmp-config.h>
11 #if HAVE_STDLIB_H
12 #include <stdlib.h>
13 #endif
14 #if HAVE_UNISTD_H
15 #include <unistd.h>
16 #endif
17 #if HAVE_STRING_H
18 #include <string.h>
19 #else
20 #include <strings.h>
21 #endif
22 #include <sys/types.h>
23 #if HAVE_NETINET_IN_H
24 #include <netinet/in.h>
25 #endif
26 #include <stdio.h>
27 #include <ctype.h>
28 #if TIME_WITH_SYS_TIME
29 # ifdef WIN32
30 # include <sys/timeb.h>
31 # else
32 # include <sys/time.h>
33 # endif
34 # include <time.h>
35 #else
36 # if HAVE_SYS_TIME_H
37 # include <sys/time.h>
38 # else
39 # include <time.h>
40 # endif
41 #endif
42 #if HAVE_SYS_SELECT_H
43 #include <sys/select.h>
44 #endif
45 #if HAVE_WINSOCK_H
46 #include <winsock.h>
47 #endif
48 #if HAVE_NETDB_H
49 #include <netdb.h>
50 #endif
51 #if HAVE_ARPA_INET_H
52 #include <arpa/inet.h>
53 #endif
55 #include <net-snmp/net-snmp-includes.h>
57 int main(int, char **);
59 #define CMD_PASSWD_NAME "passwd"
60 #define CMD_PASSWD 1
61 #define CMD_CREATE_NAME "create"
62 #define CMD_CREATE 2
63 #define CMD_DELETE_NAME "delete"
64 #define CMD_DELETE 3
65 #define CMD_CLONEFROM_NAME "cloneFrom"
66 #define CMD_CLONEFROM 4
68 #define CMD_NUM 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}
90 static
91 oid *authKeyChange = authKeyOid, *privKeyChange = privKeyOid;
92 int doauthkey = 0, doprivkey = 0;
94 void
95 usage(void)
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");
105 fprintf(stderr,
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
115 void
116 setup_oid(oid * it, size_t * len, u_char * id, size_t idlen,
117 const char *user)
119 int i, itIndex = 12;
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");
144 static void
145 optProc(int argc, char *const *argv, int opt)
147 switch (opt) {
148 case 'C':
149 while (*optarg) {
150 switch (*optarg++) {
151 case 'o':
152 authKeyChange = ownAuthKeyOid;
153 privKeyChange = ownPrivKeyOid;
154 break;
156 case 'a':
157 doauthkey = 1;
158 break;
160 case 'x':
161 doprivkey = 1;
162 break;
164 default:
165 fprintf(stderr, "Unknown flag passed to -C: %c\n",
166 optarg[-1]);
167 exit(1);
170 break;
175 main(int argc, char *argv[])
177 netsnmp_session session, *ss;
178 netsnmp_pdu *pdu = NULL, *response = NULL;
179 #ifdef notused
180 netsnmp_variable_list *vars;
181 #endif
183 int arg;
184 #ifdef notused
185 int count;
186 int current_name = 0;
187 int current_type = 0;
188 int current_value = 0;
189 char *names[128];
190 char types[128];
191 char *values[128];
192 oid name[MAX_OID_LEN];
193 #endif
194 size_t name_length = USM_OID_LEN;
195 size_t name_length2 = USM_OID_LEN;
196 int status;
197 int exitval = 0;
198 int rval;
199 int command = 0;
200 long longvar;
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)) {
220 case -2:
221 exit(0);
222 case -1:
223 usage();
224 exit(1);
225 default:
226 break;
229 SOCK_STARTUP;
232 * open an SNMP session
235 * Note: this wil obtain the engineID needed below
237 ss = snmp_open(&session);
238 if (ss == NULL) {
240 * diagnose snmp_open errors with the input netsnmp_session pointer
242 snmp_sess_perror("snmpusm", &session);
243 exit(1);
247 * create PDU for SET request and add object names and values to request
249 pdu = snmp_pdu_create(SNMP_MSG_SET);
251 if (arg >= argc) {
252 fprintf(stderr, "Please specify a opreation to perform.\n");
253 usage();
254 exit(1);
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) {
273 fprintf(stderr,
274 "New passphrase must be greater than %d characters in length.\n",
275 USM_LENGTH_P_MIN);
276 exit(1);
279 if (oldpass == NULL || strlen(oldpass) < USM_LENGTH_P_MIN) {
280 fprintf(stderr,
281 "Old passphrase must be greater than %d characters in length.\n",
282 USM_LENGTH_P_MIN);
283 exit(1);
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
302 const oid *def =
303 get_default_authtype(&session.securityAuthProtoLen);
304 session.securityAuthProto =
305 snmp_duplicate_objid(def, session.securityAuthProtoLen);
307 if (session.securityAuthProto == NULL) {
309 * assume MD5
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),
320 newKu, &newKu_len);
322 if (rval != SNMPERR_SUCCESS) {
323 snmp_perror(argv[0]);
324 fprintf(stderr, "generating the old Ku failed\n");
325 exit(1);
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),
334 oldKu, &oldKu_len);
336 if (rval != SNMPERR_SUCCESS) {
337 snmp_perror(argv[0]);
338 fprintf(stderr, "generating the new Ku failed\n");
339 exit(1);
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");
353 exit(1);
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");
364 exit(1);
368 * create the keychange string
370 rval = encode_keychange(session.securityAuthProto,
371 session.securityAuthProtoLen,
372 oldkul, oldkul_len,
373 newkul, newkul_len,
374 keychange, &keychange_len);
376 if (rval != SNMPERR_SUCCESS) {
377 snmp_perror(argv[0]);
378 fprintf(stderr, "encoding the keychange failed\n");
379 usage();
380 exit(1);
384 * add the keychange string to the outgoing packet
386 if (doauthkey) {
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);
393 if (doprivkey) {
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]
407 if (++arg >= argc) {
408 fprintf(stderr, "You must specify the user name to create\n");
409 usage();
410 exit(1);
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,
419 sizeof(longvar));
421 if (++arg < argc) {
423 * clone the new user from another user as well
425 setup_oid(usmUserCloneFrom, &name_length,
426 ss->contextEngineID, ss->contextEngineIDLen,
427 argv[arg - 1]);
428 setup_oid(usmUserSecurityName, &name_length2,
429 ss->contextEngineID, ss->contextEngineIDLen,
430 argv[arg]);
431 snmp_pdu_add_variable(pdu, usmUserCloneFrom, name_length,
432 ASN_OBJECT_ID,
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
443 if (++arg >= argc) {
444 fprintf(stderr,
445 "You must specify the user name to operate on\n");
446 usage();
447 exit(1);
450 command = CMD_CLONEFROM;
451 setup_oid(usmUserCloneFrom, &name_length,
452 ss->contextEngineID, ss->contextEngineIDLen, argv[arg]);
454 if (++arg >= argc) {
455 fprintf(stderr,
456 "You must specify the user name to clone from\n");
457 usage();
458 exit(1);
461 setup_oid(usmUserSecurityName, &name_length2,
462 ss->contextEngineID, ss->contextEngineIDLen, argv[arg]);
463 snmp_pdu_add_variable(pdu, usmUserCloneFrom, name_length,
464 ASN_OBJECT_ID,
465 (u_char *) usmUserSecurityName,
466 sizeof(oid) * name_length2);
468 } else if (strcmp(argv[arg], CMD_DELETE_NAME) == 0) {
470 * delete: delete a user
472 * delete USER
474 if (++arg >= argc) {
475 fprintf(stderr, "You must specify the user name to delete\n");
476 exit(1);
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,
485 sizeof(longvar));
486 } else {
487 fprintf(stderr, "Unknown command\n");
488 usage();
489 exit(1);
494 * do the request
496 status = snmp_synch_response(ss, pdu, &response);
497 if (status == STAT_SUCCESS) {
498 if (response) {
499 if (response->errstat == SNMP_ERR_NOERROR) {
500 fprintf(stderr, "%s\n", successNotes[command - 1]);
501 } else {
502 fprintf(stderr, "Error in packet.\nReason: %s\n",
503 snmp_errstring(response->errstat));
504 if (response->errindex != 0) {
505 int count;
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++)
511 /*EMPTY*/;
512 if (vars)
513 fprint_objid(stderr, vars->name,
514 vars->name_length);
515 fprintf(stderr, "\n");
517 exitval = 2;
520 } else if (status == STAT_TIMEOUT) {
521 fprintf(stderr, "Timeout: No Response from %s\n",
522 session.peername);
523 exitval = 1;
524 } else { /* status == STAT_ERROR */
525 snmp_sess_perror("snmpset", ss);
526 exitval = 1;
529 if (response)
530 snmp_free_pdu(response);
531 snmp_close(ss);
532 SOCK_CLEANUP;
533 return exitval;