added files
[bcm963xx.git] / userapps / opensource / net-snmp / apps / snmpusm.c
1 /*
2  * snmpusm.c - send snmp SET requests to a network entity to change the
3  *             usm user database
4  *
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>
10
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
54
55 #include <net-snmp/net-snmp-includes.h>
56
57 int             main(int, char **);
58
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
67
68 #define CMD_NUM    4
69
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."
75 };
76
77 #define                   USM_OID_LEN    12
78
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}
87
88 ;
89
90 static
91 oid            *authKeyChange = authKeyOid, *privKeyChange = privKeyOid;
92 int             doauthkey = 0, doprivkey = 0;
93
94 void
95 usage(void)
96 {
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");
110 }
111
112 /*
113  * setup_oid appends to the oid the index for the engineid/user 
114  */
115 void
116 setup_oid(oid * it, size_t * len, u_char * id, size_t idlen,
117           const char *user)
118 {
119     int             i, itIndex = 12;
120
121     *len = itIndex + 1 + idlen + 1 + strlen(user);
122
123     it[itIndex++] = idlen;
124     for (i = 0; i < (int) idlen; i++) {
125         it[itIndex++] = id[i];
126     }
127
128     it[itIndex++] = strlen(user);
129     for (i = 0; i < (int) strlen(user); i++) {
130         it[itIndex++] = user[i];
131     }
132
133     /*
134      * fprintf(stdout, "setup_oid: ");  
135      */
136     /*
137      * fprint_objid(stdout, it, *len);  
138      */
139     /*
140      * fprintf(stdout, "\n");  
141      */
142 }
143
144 static void
145 optProc(int argc, char *const *argv, int opt)
146 {
147     switch (opt) {
148     case 'C':
149         while (*optarg) {
150             switch (*optarg++) {
151             case 'o':
152                 authKeyChange = ownAuthKeyOid;
153                 privKeyChange = ownPrivKeyOid;
154                 break;
155
156             case 'a':
157                 doauthkey = 1;
158                 break;
159
160             case 'x':
161                 doprivkey = 1;
162                 break;
163
164             default:
165                 fprintf(stderr, "Unknown flag passed to -C: %c\n",
166                         optarg[-1]);
167                 exit(1);
168             }
169         }
170         break;
171     }
172 }
173
174 int
175 main(int argc, char *argv[])
176 {
177     netsnmp_session session, *ss;
178     netsnmp_pdu    *pdu = NULL, *response = NULL;
179 #ifdef notused
180     netsnmp_variable_list *vars;
181 #endif
182
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;
201
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;
206
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];
212
213     authKeyChange = authKeyOid;
214     privKeyChange = privKeyOid;
215
216     /*
217      * get the common command line arguments 
218      */
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;
227     }
228
229     SOCK_STARTUP;
230
231     /*
232      * open an SNMP session 
233      */
234     /*
235      * Note:  this wil obtain the engineID needed below 
236      */
237     ss = snmp_open(&session);
238     if (ss == NULL) {
239         /*
240          * diagnose snmp_open errors with the input netsnmp_session pointer 
241          */
242         snmp_sess_perror("snmpusm", &session);
243         exit(1);
244     }
245
246     /*
247      * create PDU for SET request and add object names and values to request 
248      */
249     pdu = snmp_pdu_create(SNMP_MSG_SET);
250
251     if (arg >= argc) {
252         fprintf(stderr, "Please specify a opreation to perform.\n");
253         usage();
254         exit(1);
255     }
256
257     if (strcmp(argv[arg], CMD_PASSWD_NAME) == 0) {
258
259         /*
260          * passwd: change a users password.
261          *
262          * XXX:  Uses the auth type of the calling user, a MD5 user can't
263          *       change a SHA user's key.
264          */
265         command = CMD_PASSWD;
266         oldpass = argv[++arg];
267         newpass = argv[++arg];
268
269         if (doprivkey == 0 && doauthkey == 0)
270             doprivkey = doauthkey = 1;
271
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);
277         }
278
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);
284         }
285
286         /*
287          * do we have a securityName?  If not, copy the default 
288          */
289         if (session.securityName == NULL) {
290             session.securityName = 
291               strdup(netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
292                                            NETSNMP_DS_LIB_SECNAME));
293         }
294
295         /*
296          * the old Ku is in the session, but we need the new one 
297          */
298         if (session.securityAuthProto == NULL) {
299             /*
300              * get .conf set default 
301              */
302             const oid      *def =
303                 get_default_authtype(&session.securityAuthProtoLen);
304             session.securityAuthProto =
305                 snmp_duplicate_objid(def, session.securityAuthProtoLen);
306         }
307         if (session.securityAuthProto == NULL) {
308             /*
309              * assume MD5 
310              */
311             session.securityAuthProtoLen =
312                 sizeof(usmHMACMD5AuthProtocol) / sizeof(oid);
313             session.securityAuthProto =
314                 snmp_duplicate_objid(usmHMACMD5AuthProtocol,
315                                      session.securityAuthProtoLen);
316         }
317         rval = generate_Ku(session.securityAuthProto,
318                            session.securityAuthProtoLen,
319                            (u_char *) newpass, strlen(newpass),
320                            newKu, &newKu_len);
321
322         if (rval != SNMPERR_SUCCESS) {
323             snmp_perror(argv[0]);
324             fprintf(stderr, "generating the old Ku failed\n");
325             exit(1);
326         }
327
328         /*
329          * the old Ku is in the session, but we need the new one 
330          */
331         rval = generate_Ku(session.securityAuthProto,
332                            session.securityAuthProtoLen,
333                            (u_char *) oldpass, strlen(oldpass),
334                            oldKu, &oldKu_len);
335
336         if (rval != SNMPERR_SUCCESS) {
337             snmp_perror(argv[0]);
338             fprintf(stderr, "generating the new Ku failed\n");
339             exit(1);
340         }
341
342         /*
343          * generate the two Kul's 
344          */
345         rval = generate_kul(session.securityAuthProto,
346                             session.securityAuthProtoLen,
347                             ss->contextEngineID, ss->contextEngineIDLen,
348                             oldKu, oldKu_len, oldkul, &oldkul_len);
349
350         if (rval != SNMPERR_SUCCESS) {
351             snmp_perror(argv[0]);
352             fprintf(stderr, "generating the old Kul failed\n");
353             exit(1);
354         }
355
356         rval = generate_kul(session.securityAuthProto,
357                             session.securityAuthProtoLen,
358                             ss->contextEngineID, ss->contextEngineIDLen,
359                             newKu, newKu_len, newkul, &newkul_len);
360
361         if (rval != SNMPERR_SUCCESS) {
362             snmp_perror(argv[0]);
363             fprintf(stderr, "generating the new Kul failed\n");
364             exit(1);
365         }
366
367         /*
368          * create the keychange string 
369          */
370         rval = encode_keychange(session.securityAuthProto,
371                                 session.securityAuthProtoLen,
372                                 oldkul, oldkul_len,
373                                 newkul, newkul_len,
374                                 keychange, &keychange_len);
375
376         if (rval != SNMPERR_SUCCESS) {
377             snmp_perror(argv[0]);
378             fprintf(stderr, "encoding the keychange failed\n");
379             usage();
380             exit(1);
381         }
382
383         /*
384          * add the keychange string to the outgoing packet 
385          */
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);
392         }
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);
399         }
400
401     } else if (strcmp(argv[arg], CMD_CREATE_NAME) == 0) {
402         /*
403          * create:  create a user
404          *
405          * create USER [CLONEFROM]
406          */
407         if (++arg >= argc) {
408             fprintf(stderr, "You must specify the user name to create\n");
409             usage();
410             exit(1);
411         }
412
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));
420
421         if (++arg < argc) {
422             /*
423              * clone the new user from another user as well 
424              */
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);
435         }
436
437     } else if (strcmp(argv[arg], CMD_CLONEFROM_NAME) == 0) {
438         /*
439          * create:  clone a user from another
440          *
441          * cloneFrom USER FROM
442          */
443         if (++arg >= argc) {
444             fprintf(stderr,
445                     "You must specify the user name to operate on\n");
446             usage();
447             exit(1);
448         }
449
450         command = CMD_CLONEFROM;
451         setup_oid(usmUserCloneFrom, &name_length,
452                   ss->contextEngineID, ss->contextEngineIDLen, argv[arg]);
453
454         if (++arg >= argc) {
455             fprintf(stderr,
456                     "You must specify the user name to clone from\n");
457             usage();
458             exit(1);
459         }
460
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);
467
468     } else if (strcmp(argv[arg], CMD_DELETE_NAME) == 0) {
469         /*
470          * delete:  delete a user
471          *
472          * delete USER
473          */
474         if (++arg >= argc) {
475             fprintf(stderr, "You must specify the user name to delete\n");
476             exit(1);
477         }
478
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);
490     }
491
492
493     /*
494      * do the request 
495      */
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");
516                 }
517                 exitval = 2;
518             }
519         }
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;
527     }
528
529     if (response)
530         snmp_free_pdu(response);
531     snmp_close(ss);
532     SOCK_CLEANUP;
533     return exitval;
534 }