blob: 8da3980e5778eae43e67407fb5e67bca2aa04cb0 [file] [log] [blame]
Wes Hardaker87bed831999-04-06 22:13:53 +00001/*
2 * encode_keychange.c
3 *
4 * Collect information to build a KeyChange encoding, per the textual
5 * convention given in RFC 2274, Section 5. Compute the value and
6 * dump to stdout as a string of hex nibbles.
7 *
8 *
9 * Passphrase material may come from many sources. The following are
10 * checked in order (see get_user_passphrases()):
11 * - Prompt always if -f is given.
12 * - Commandline arguments.
13 * - PASSPHRASE_FILE.
14 * - Prompts on stdout. Use -P to turn off prompt tags.
15 *
16 *
17 * FIX Better name?
18 * FIX Change encode_keychange() to take random bits?
19 * FIX QUITFUN not quite appropriate here...
20 * FIX This is slow...
21 */
22
Wes Hardakerfa26a931999-05-03 19:58:40 +000023#include <config.h>
Wes Hardaker87bed831999-04-06 22:13:53 +000024
Wes Hardakerfa26a931999-05-03 19:58:40 +000025#include <stdio.h>
26#include <ctype.h>
Michael Slifcakd3d86411999-07-27 19:24:03 +000027#include <sys/types.h>
Wes Hardakerfa26a931999-05-03 19:58:40 +000028#include <sys/stat.h>
Michael Slifcakd3d86411999-07-27 19:24:03 +000029#if HAVE_UNISTD_H
Wes Hardakerfa26a931999-05-03 19:58:40 +000030#include <unistd.h>
Michael Slifcakd3d86411999-07-27 19:24:03 +000031#endif
Wes Hardakerfa26a931999-05-03 19:58:40 +000032#if HAVE_STRING_H
33#include <string.h>
34#else
35#include <strings.h>
36#endif
37#ifdef HAVE_NETINET_IN_H
38#include <netinet/in.h>
39#endif
40
Michael Slifcakd3d86411999-07-27 19:24:03 +000041#if HAVE_WINSOCK_H
42#include <winsock.h>
43#endif
44
Wes Hardakerfa26a931999-05-03 19:58:40 +000045#include "asn1.h"
46#include "snmp_api.h"
47#include "tools.h"
48#include "scapi.h"
49#include "snmpv3.h"
50#include "keytools.h"
51#include "snmp_debug.h"
52#include "callback.h"
Wes Hardaker87bed831999-04-06 22:13:53 +000053
54#include "../snmplib/transform_oids.h"
55
56#include <stdlib.h>
57
Wes Hardaker87bed831999-04-06 22:13:53 +000058/*
59 * Globals, &c...
60 */
61char *local_progname;
62
63#define NL "\n"
64
65#define USAGE "Usage: %s [-fhPvV] -t (md5|sha1) [-O \"<old_passphrase>\"][-N \"<new_passphrase>\"][-E [0x]<engineID>]"
66
67#define OPTIONLIST "E:fhN:O:Pt:vVD"
68
69#define PASSPHRASE_DIR ".snmp"
70 /* Rooted at $HOME.
71 */
72#define PASSPHRASE_FILE PASSPHRASE_DIR ## "/passphrase.ek"
73 /*
74 * Format: two lines containing old and new passphrases, nothing more.
75 *
76 * XXX Add creature comforts like: comments and
77 * tokens identifying passphrases, separate directory check,
78 * check in current directory (?), traverse a path of
79 * directories (?)...
80 * FIX Better name?
81 */
82
Wes Hardaker87bed831999-04-06 22:13:53 +000083
84int forcepassphrase = 0, /* Always prompt for passphrases. */
85 promptindicator = 1, /* Output an indicator that input
86 * is requested. */
87 visible = 0, /* Echo passphrases to terminal. */
Niels Baggesen0045e2f1999-05-03 22:40:11 +000088 verbose = 0; /* Output progress to stderr. */
89size_t engineid_len = 0;
Wes Hardaker87bed831999-04-06 22:13:53 +000090
Niels Baggesen0045e2f1999-05-03 22:40:11 +000091u_char *engineid = NULL; /* Both input & final binary form.*/
92char *newpass = NULL,
Wes Hardaker87bed831999-04-06 22:13:53 +000093 *oldpass = NULL;
94
95char *transform_type_input = NULL;
96
97oid *transform_type = NULL; /* Type of HMAC hash to use. */
98
99
100
101/*
102 * Prototypes.
103 */
Michael Slifcak28eb2ba1999-05-27 12:16:26 +0000104void usage_to_file(FILE *ofp);
Wes Hardaker87bed831999-04-06 22:13:53 +0000105void usage_synopsis(FILE *ofp);
Michael Slifcak81962ed1999-04-07 13:17:28 +0000106int get_user_passphrases(void);
Niels Baggesen0045e2f1999-05-03 22:40:11 +0000107int snmp_ttyecho(const int fd, const int echo);
Niels Baggesend4d09ce1999-04-26 19:09:35 +0000108char *snmp_getpassphrase(const char *prompt, int fvisible);
Wes Hardaker87bed831999-04-06 22:13:53 +0000109
Michael Slifcakd3d86411999-07-27 19:24:03 +0000110#ifdef WIN32
111#define HAVE_GETPASS 1
112char *getpass( const char * prompt );
113int isatty(int);
114int _cputs(const char *);
115int _getch(void);
116#endif
117
Wes Hardaker87bed831999-04-06 22:13:53 +0000118/*******************************************************************-o-******
119 */
120int
121main(int argc, char **argv)
122{
Michael Slifcakd3d86411999-07-27 19:24:03 +0000123 int rval = SNMPERR_SUCCESS;
124 size_t oldKu_len = SNMP_MAXBUF_SMALL,
125 newKu_len = SNMP_MAXBUF_SMALL,
126 oldkul_len = SNMP_MAXBUF_SMALL,
127 newkul_len = SNMP_MAXBUF_SMALL,
128 keychange_len = SNMP_MAXBUF_SMALL;
Wes Hardaker87bed831999-04-06 22:13:53 +0000129
Michael Slifcakd3d86411999-07-27 19:24:03 +0000130 char *s = NULL;
131 u_char oldKu[SNMP_MAXBUF_SMALL],
132 newKu[SNMP_MAXBUF_SMALL],
133 oldkul[SNMP_MAXBUF_SMALL],
134 newkul[SNMP_MAXBUF_SMALL],
135 keychange[SNMP_MAXBUF_SMALL];
Wes Hardaker87bed831999-04-06 22:13:53 +0000136
Michael Slifcakd3d86411999-07-27 19:24:03 +0000137 int i;
138 int arg = 1;
Wes Hardaker87bed831999-04-06 22:13:53 +0000139
140 local_progname = argv[0];
141
Wes Hardaker87bed831999-04-06 22:13:53 +0000142
143
144 /*
145 * Parse.
146 */
Michael Slifcakd3d86411999-07-27 19:24:03 +0000147 for(; (arg < argc) && (argv[arg][0] == '-') ; arg++){
148 switch(argv[arg][1]){
149 case 'D': snmp_set_do_debugging(1); break;
150 case 'E': engineid = (u_char *)argv[++arg]; break;
151 case 'f': forcepassphrase = 1; break;
152 case 'N': newpass = argv[++arg]; break;
153 case 'O': oldpass = argv[++arg]; break;
154 case 'P': promptindicator = 0; break;
155 case 't': transform_type_input = argv[++arg]; break;
156 case 'v': verbose = 1; break;
157 case 'V': visible = 1; break;
Wes Hardaker87bed831999-04-06 22:13:53 +0000158 case 'h':
159 rval = 0;
160 default:
Michael Slifcak28eb2ba1999-05-27 12:16:26 +0000161 usage_to_file(stdout);
Wes Hardaker87bed831999-04-06 22:13:53 +0000162 exit(rval);
163 }
Michael Slifcakd3d86411999-07-27 19:24:03 +0000164 }
Wes Hardaker87bed831999-04-06 22:13:53 +0000165
Michael Slifcakd3d86411999-07-27 19:24:03 +0000166 if ( !transform_type_input ) {
Wes Hardaker87bed831999-04-06 22:13:53 +0000167 fprintf(stderr, "The -t option is mandatory.\n");
168 usage_synopsis(stdout);
169 exit(1000);
170 }
171
172
173
174 /*
175 * Convert and error check transform_type.
176 */
177 if ( !strcmp(transform_type_input, "md5") ) {
178 transform_type = usmHMACMD5AuthProtocol;
179
180 } else if ( !strcmp(transform_type_input, "sha1") ) {
181 transform_type = usmHMACSHA1AuthProtocol;
182
183 } else {
184 fprintf(stderr,
185 "Unrecognized hash transform: \"%s\".\n",
186 transform_type_input);
187 usage_synopsis(stderr);
188 QUITFUN(rval = SNMPERR_GENERR, main_quit);
189 }
190
191 if (verbose) {
Michael Slifcak2ca44431999-07-27 14:52:37 +0000192 fprintf(stderr, "Hash:\t\t%s\n",
Wes Hardaker87bed831999-04-06 22:13:53 +0000193 (transform_type == usmHMACMD5AuthProtocol)
194 ? "usmHMACMD5AuthProtocol"
195 : "usmHMACSHA1AuthProtocol"
196 );
197 }
198
199
200
201 /*
202 * Build engineID. Accept hex engineID as the bits
203 * "in-and-of-themselves", otherwise create an engineID with the
204 * given string as text.
205 *
206 * If no engineID is given, lookup the first IP address for the
207 * localhost and use that (see setup_engineID()).
208 */
209 if ( engineid && (tolower(*(engineid+1)) == 'x') ) {
210 engineid_len = hex_to_binary2( engineid+2,
Niels Baggesen0045e2f1999-05-03 22:40:11 +0000211 strlen((char *)engineid)-2,
Wes Hardaker87bed831999-04-06 22:13:53 +0000212 (char **) &engineid);
Wes Hardaker5b8e0c61999-04-07 18:32:03 +0000213 DEBUGMSGTL(("encode_keychange","engineIDLen: %d\n", engineid_len));
Wes Hardaker87bed831999-04-06 22:13:53 +0000214 } else {
Niels Baggesen0045e2f1999-05-03 22:40:11 +0000215 engineid_len = setup_engineID(&engineid, (char *)engineid);
Wes Hardaker87bed831999-04-06 22:13:53 +0000216
217 }
218
219#ifdef SNMP_TESTING_CODE
220 if (verbose) {
Michael Slifcak2ca44431999-07-27 14:52:37 +0000221 fprintf(stderr, "EngineID:\t%s\n",
Wes Hardaker87bed831999-04-06 22:13:53 +0000222 /* XXX = */ dump_snmpEngineID(engineid, &engineid_len));
223 }
224#endif
225
226
227 /*
228 * Get passphrases from user.
229 */
230 rval = get_user_passphrases();
231 QUITFUN(rval, main_quit);
232
233 if ( strlen(oldpass) < USM_LENGTH_P_MIN ) {
234 fprintf(stderr, "Old passphrase must be greater than %d "
235 "characters in length.\n",
236 USM_LENGTH_P_MIN);
237 QUITFUN(rval = SNMPERR_GENERR, main_quit);
238
239 } else if ( strlen(newpass) < USM_LENGTH_P_MIN ) {
240 fprintf(stderr, "New passphrase must be greater than %d "
241 "characters in length.\n",
242 USM_LENGTH_P_MIN);
243 QUITFUN(rval = SNMPERR_GENERR, main_quit);
244 }
245
246 if (verbose) {
Michael Slifcak2ca44431999-07-27 14:52:37 +0000247 fprintf(stderr,
Wes Hardaker87bed831999-04-06 22:13:53 +0000248 "Old passphrase:\t%s\nNew passphrase:\t%s\n",
249 oldpass, newpass);
250 }
251
252
253
254 /*
255 * Compute Ku and Kul's from old and new passphrases, then
256 * compute the keychange string & print it out.
257 */
258 rval = sc_init();
259 QUITFUN(rval, main_quit);
260
261
262 rval = generate_Ku( transform_type, USM_LENGTH_OID_TRANSFORM,
Niels Baggesen0045e2f1999-05-03 22:40:11 +0000263 (u_char *)oldpass, strlen(oldpass),
Wes Hardaker87bed831999-04-06 22:13:53 +0000264 oldKu, &oldKu_len);
265 QUITFUN(rval, main_quit);
266
267
268 rval = generate_Ku( transform_type, USM_LENGTH_OID_TRANSFORM,
Niels Baggesen0045e2f1999-05-03 22:40:11 +0000269 (u_char *)newpass, strlen(newpass),
Wes Hardaker87bed831999-04-06 22:13:53 +0000270 newKu, &newKu_len);
271 QUITFUN(rval, main_quit);
272
273
Wes Hardaker5b8e0c61999-04-07 18:32:03 +0000274 DEBUGMSGTL(("encode_keychange", "EID (%d): ", engineid_len));
Michael Slifcakd3d86411999-07-27 19:24:03 +0000275 for(i=0; i < (int)engineid_len; i++)
Wes Hardaker5b8e0c61999-04-07 18:32:03 +0000276 DEBUGMSGTL(("encode_keychange", "%02x",(int) (engineid[i])));
277 DEBUGMSGTL(("encode_keychange","\n"));
Wes Hardaker87bed831999-04-06 22:13:53 +0000278
Wes Hardaker5b8e0c61999-04-07 18:32:03 +0000279 DEBUGMSGTL(("encode_keychange", "old Ku (%d) (from %s): ", oldKu_len, oldpass));
Michael Slifcakd3d86411999-07-27 19:24:03 +0000280 for(i=0; i < (int)oldKu_len; i++)
Wes Hardaker5b8e0c61999-04-07 18:32:03 +0000281 DEBUGMSGTL(("encode_keychange", "%02x",(int) (oldKu[i])));
282 DEBUGMSGTL(("encode_keychange","\n"));
Wes Hardaker87bed831999-04-06 22:13:53 +0000283
284 rval = generate_kul( transform_type, USM_LENGTH_OID_TRANSFORM,
285 engineid, engineid_len,
286 oldKu, oldKu_len,
287 oldkul, &oldkul_len);
288 QUITFUN(rval, main_quit);
289
290
Wes Hardaker5b8e0c61999-04-07 18:32:03 +0000291 DEBUGMSGTL(("encode_keychange", "generating old Kul (%d) (from Ku): ", oldkul_len));
Michael Slifcakd3d86411999-07-27 19:24:03 +0000292 for(i=0; i < (int)oldkul_len; i++)
Wes Hardaker5b8e0c61999-04-07 18:32:03 +0000293 DEBUGMSGTL(("encode_keychange", "%02x",(int) (oldkul[i])));
294 DEBUGMSGTL(("encode_keychange","\n"));
Wes Hardaker87bed831999-04-06 22:13:53 +0000295
296 rval = generate_kul( transform_type, USM_LENGTH_OID_TRANSFORM,
297 engineid, engineid_len,
298 newKu, newKu_len,
299 newkul, &newkul_len);
300 QUITFUN(rval, main_quit);
301
Wes Hardaker5b8e0c61999-04-07 18:32:03 +0000302 DEBUGMSGTL(("encode_keychange", "generating new Kul (%d) (from Ku): ", oldkul_len));
Michael Slifcakd3d86411999-07-27 19:24:03 +0000303 for(i=0; i < (int)newkul_len; i++)
Wes Hardaker5b8e0c61999-04-07 18:32:03 +0000304 DEBUGMSGTL(("encode_keychange", "%02x",newkul[i]));
305 DEBUGMSGTL(("encode_keychange","\n"));
Wes Hardaker87bed831999-04-06 22:13:53 +0000306
307 rval = encode_keychange(transform_type, USM_LENGTH_OID_TRANSFORM,
308 oldkul, oldkul_len,
309 newkul, newkul_len,
310 keychange, &keychange_len);
311 QUITFUN(rval, main_quit);
312
313
314
315 binary_to_hex(keychange, keychange_len, &s);
316 printf("%s%s\n",
317 (verbose) ? "KeyChange string:\t" : "", /* XXX stdout */
318 s);
319
320
321 /*
322 * Cleanup.
323 */
324main_quit:
Wes Hardakerfa26a931999-05-03 19:58:40 +0000325 snmp_call_callbacks(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_SHUTDOWN,
326 NULL);
327
Wes Hardaker87bed831999-04-06 22:13:53 +0000328
329 SNMP_ZERO(oldpass, strlen(oldpass));
330 SNMP_ZERO(newpass, strlen(newpass));
331
332 SNMP_ZERO(oldKu, oldKu_len);
333 SNMP_ZERO(newKu, newKu_len);
334
335 SNMP_ZERO(oldkul, oldkul_len);
336 SNMP_ZERO(newkul, newkul_len);
337
338 SNMP_ZERO(s, strlen(s));
339
340 return rval;
341
342} /* end main() */
343
344
345
346
347/*******************************************************************-o-******
348 */
349void
350usage_synopsis(FILE *ofp)
351{
Niels Baggesen0045e2f1999-05-03 22:40:11 +0000352 fprintf(ofp, USAGE "\n\
353\n\
354 -E [0x]<engineID> EngineID used for kul generation.\n\
355 -f Force passphrases to be read from stdin.\n\
356 -h Help.\n\
357 -N \"<new_passphrase>\" Passphrase used to generate new Ku.\n\
358 -O \"<old_passphrase>\" Passphrase used to generate old Ku.\n\
359 -P Turn off prompt indicators.\n\
360 -t md5 | sha1 HMAC hash transform type.\n\
361 -v Verbose.\n\
362 -V Visible. Echo passphrases to terminal.\n\
Wes Hardaker87bed831999-04-06 22:13:53 +0000363 "
364 NL, local_progname);
365
366} /* end usage_synopsis() */
367
368void
Michael Slifcak28eb2ba1999-05-27 12:16:26 +0000369usage_to_file(FILE *ofp)
Wes Hardaker87bed831999-04-06 22:13:53 +0000370{
371 char *s;
372
373 usage_synopsis(ofp);
374
375 fprintf(ofp,
Niels Baggesen0045e2f1999-05-03 22:40:11 +0000376 "\n\
377 Only -t is mandatory. The transform is used to convert P=>Ku, convert\n\
378 Ku=>Kul, and to hash the old Kul with the random bits.\n\
379\n\
380 Passphrase will be taken from the first successful source as follows:\n\
381 a) Commandline options,\n\
382 b) The file \"%s/%s\",\n\
383 c) stdin -or- User input from the terminal.\n\
384\n\
385 -f will require reading from the stdin/terminal, ignoring a) and b).\n\
386 -P will prevent prompts for passphrases to stdout from being printed.\n\
387\n\
388 <engineID> is intepreted as a hex string when preceeded by \"0x\",\n\
389 otherwise it is created to contain \"text\". If nothing is given,\n\
390 <engineID> is constructed from the first IP address for the local host.\n\
Wes Hardaker87bed831999-04-06 22:13:53 +0000391 "
392 NL, (s = getenv("HOME"))?s:"$HOME", PASSPHRASE_FILE);
393
394
395/* FIX -- make this possible?
396 -r [0x]<random_bits> Random bits used in KeyChange XOR.
397
398 <engineID> and <random_bits> are intepreted as hex strings when
399 preceeded by \"0x\", otherwise <engineID> is created to contain \"text\"
400 and <random_bits> are the same as the ascii input.
401
402 <random_bits> will be generated by SCAPI if not given. If value is
403 too long, it will be truncated; if too short, the remainder will be
404 filled in with zeros.
405 */
406
407} /* end usage() */
408
409
Michael Slifcak19c93a21999-07-30 13:46:22 +0000410/* this defined for HPUX aCC because the aCC doesn't drop the */
411/* snmp_parse_args.c functionality if compile with -g, PKY */
Michael Slifcak28eb2ba1999-05-27 12:16:26 +0000412
Michael Slifcak771c88e1999-07-12 01:36:24 +0000413void usage(void)
Michael Slifcak28eb2ba1999-05-27 12:16:26 +0000414{
415 usage_to_file(stdout);
416}
417
418
Wes Hardaker87bed831999-04-06 22:13:53 +0000419
420
421
422/*******************************************************************-o-******
423 * get_user_passphrases
424 *
425 * Returns:
426 * SNMPERR_SUCCESS Success.
427 * SNMPERR_GENERR Otherwise.
428 *
429 *
430 * Acquire new and old passphrases from the user:
431 *
432 * + Always prompt if 'forcepassphrase' is set.
433 * + Use given arguments if they are defined.
434 * + Otherwise read file format from PASSWORD_FILE.
435 * Sanity check existence and permissions of the path.
436 * ASSUME for now that PASSWORD_FILE is rooted only at $HOME.
437 * + Otherwise prompt user for passphrase(s).
438 * Echo input if 'visible' is set.
439 * Turning off 'promptindicator' makes piping in input cleaner.
440 *
441 * NOTE Only using forcepassphrase mandates taking both passphrases
442 * from the same source. Otherwise processing continues until both
443 * passphrases are defined.
444 */
445int
446get_user_passphrases(void)
447{
Niels Baggesen0045e2f1999-05-03 22:40:11 +0000448 int rval = SNMPERR_SUCCESS;
449 size_t len;
Wes Hardaker87bed831999-04-06 22:13:53 +0000450
Niels Baggesen0045e2f1999-05-03 22:40:11 +0000451 char *obuf = NULL,
Wes Hardaker87bed831999-04-06 22:13:53 +0000452 *nbuf = NULL;
453
454 char path[SNMP_MAXBUF],
455 buf[SNMP_MAXBUF],
456 *s = NULL;
457
458 struct stat statbuf;
459 FILE *fp;
460
Wes Hardaker87bed831999-04-06 22:13:53 +0000461
462
463 /*
464 * Allow prompts to the user to override all other sources.
465 * Nothing to do otherwise if oldpass and newpass are already defined.
466 */
467 if ( forcepassphrase ) goto get_user_passphrases_prompt;
468 if ( oldpass && newpass ) goto get_user_passphrases_quit;
469
470
471
472 /*
473 * Read passphrases out of PASSPHRASE_FILE. Sanity check the
474 * path for existence and access first. Refuse to read
475 * if the permissions are wrong.
476 */
477 s = getenv("HOME");
478 sprintf(path, "%s/%s", s, PASSPHRASE_DIR);
479
480 /* Test directory. */
481 if ( stat(path, &statbuf) < 0 ) {
482 fprintf(stderr, "Cannot access directory \"%s\".\n", path);
483 QUITFUN(rval = SNMPERR_GENERR, get_user_passphrases_quit);
Michael Slifcakd3d86411999-07-27 19:24:03 +0000484#ifndef WIN32
Wes Hardaker87bed831999-04-06 22:13:53 +0000485 } else if ( statbuf.st_mode & (S_IRWXG|S_IRWXO) ) {
486 fprintf(stderr,
487 "Directory \"%s\" is accessible by group or world.\n",
488 path);
489 QUITFUN(rval = SNMPERR_GENERR, get_user_passphrases_quit);
Michael Slifcakd3d86411999-07-27 19:24:03 +0000490#endif /* !WIN32 */
Wes Hardaker87bed831999-04-06 22:13:53 +0000491 }
492
493 /* Test file. */
494 sprintf(path, "%s/%s", s, PASSPHRASE_FILE);
495 if ( stat(path, &statbuf) < 0 ) {
496 fprintf(stderr, "Cannot access file \"%s\".\n", path);
497 QUITFUN(rval = SNMPERR_GENERR, get_user_passphrases_quit);
Michael Slifcakd3d86411999-07-27 19:24:03 +0000498#ifndef WIN32
Wes Hardaker87bed831999-04-06 22:13:53 +0000499 } else if ( statbuf.st_mode & (S_IRWXG|S_IRWXO) ) {
500 fprintf(stderr,
501 "File \"%s\" is accessible by group or world.\n", path);
502 QUITFUN(rval = SNMPERR_GENERR, get_user_passphrases_quit);
Michael Slifcakd3d86411999-07-27 19:24:03 +0000503#endif /* !WIN32 */
Wes Hardaker87bed831999-04-06 22:13:53 +0000504 }
505
506 /* Open the file. */
Niels Baggesen0045e2f1999-05-03 22:40:11 +0000507 if ( (fp = fopen(path, "r")) == NULL ) {
Wes Hardaker87bed831999-04-06 22:13:53 +0000508 fprintf(stderr, "Cannot open \"%s\".", path);
509 QUITFUN(rval = SNMPERR_GENERR, get_user_passphrases_quit);
510 }
511
512 /* Read 1st line. */
Michael Slifcak59d6b351999-04-07 19:23:22 +0000513 if ( !fgets(buf, sizeof(buf), fp) ) {
Wes Hardaker87bed831999-04-06 22:13:53 +0000514 if ( verbose ) {
Michael Slifcak2ca44431999-07-27 14:52:37 +0000515 fprintf(stderr,
Wes Hardaker87bed831999-04-06 22:13:53 +0000516 "Passphrase file \"%s\" is empty...\n", path);
517 }
518 goto get_user_passphrases_prompt;
519
520 } else if ( !oldpass ) {
521 len = strlen(buf);
522 if ( buf[len-1] == '\n' ) buf[--len] = '\0';
Michael Slifcakafb22b81999-11-05 14:22:52 +0000523 oldpass = (char *)calloc(1,len+1);
Wes Hardaker87bed831999-04-06 22:13:53 +0000524 memcpy(oldpass, buf, len+1);
525 }
526 /* Read 2nd line. */
Michael Slifcak59d6b351999-04-07 19:23:22 +0000527 if ( !fgets(buf, sizeof(buf), fp) ) {
Wes Hardaker87bed831999-04-06 22:13:53 +0000528 if ( verbose ) {
Michael Slifcak2ca44431999-07-27 14:52:37 +0000529 fprintf(stderr,
Wes Hardaker87bed831999-04-06 22:13:53 +0000530 "Only one line in file \"%s\"...\n", path);
531 }
532
533 } else if ( !newpass ) {
534 len = strlen(buf);
535 if ( buf[len-1] == '\n' ) buf[--len] = '\0';
Michael Slifcakafb22b81999-11-05 14:22:52 +0000536 newpass = (char *)calloc(1,len+1);
Wes Hardaker87bed831999-04-06 22:13:53 +0000537 memcpy(newpass, buf, len+1);
538 }
539
540 if ( oldpass && newpass ) goto get_user_passphrases_quit;
541
542
543
544 /*
545 * Prompt the user for passphrase entry. Visible prompts
546 * may be omitted, and invisible entry may turned off.
547 */
548get_user_passphrases_prompt:
549 if ( forcepassphrase ) {
550 oldpass = newpass = NULL;
551 }
552
553 if ( ! oldpass ) {
554 oldpass = obuf
555 = snmp_getpassphrase(
556 (promptindicator) ? "Old passphrase: " : "",
557 visible);
558 }
559 if ( ! newpass ) {
560 newpass = nbuf
561 = snmp_getpassphrase(
562 (promptindicator) ? "New passphrase: " : "",
563 visible);
564 }
565
566
567
568 /*
569 * Check that both passphrases were defined.
570 */
571 if ( oldpass && newpass ) {
572 goto get_user_passphrases_quit;
573 } else {
574 rval = SNMPERR_GENERR;
575 }
576
577
578get_user_passphrases_quit:
579 SNMP_ZERO(buf, SNMP_MAXBUF);
580
581 if ( obuf != oldpass ) {
582 SNMP_ZERO(obuf, strlen(obuf));
583 SNMP_FREE(obuf);
584 }
585 if ( nbuf != newpass ) {
586 SNMP_ZERO(nbuf, strlen(nbuf));
587 SNMP_FREE(nbuf);
588 }
589
590 return rval;
591
592} /* end get_user_passphrases() */
Michael Slifcak59d6b351999-04-07 19:23:22 +0000593
594/*******************************************************************-o-******
595 * snmp_ttyecho
596 *
597 * Parameters:
598 * fd Descriptor of terminal on which to toggle echoing.
599 * echo TRUE if echoing should be on; FALSE otherwise.
600 *
601 * Returns:
602 * Previous value of echo setting.
603 *
604 *
605 * FIX Put HAVE_TCGETATTR in autoconf?
606 */
607#ifndef HAVE_GETPASS
608#ifdef HAVE_TCGETATTR
609#include <termios.h>
610int
611snmp_ttyecho(const int fd, const int echo)
612{
613 struct termios tio;
614 int was_echo;
615
616
617 if (!isatty(fd))
618 return (-1);
619 tcgetattr(fd, &tio);
620 was_echo = (tio.c_lflag & ECHO) != 0;
621 if (echo)
622 tio.c_lflag |= (ECHO | ECHONL);
623 else
624 tio.c_lflag &= ~(ECHO | ECHONL);
625 tcsetattr(fd, TCSANOW, &tio);
626
627 return (was_echo);
628
629} /* end snmp_ttyecho() */
630
631#else
632#include <sgtty.h>
633int
634snmp_ttyecho(const int fd, const int echo)
635{
636 struct sgttyb ttyparams;
637 int was_echo;
638
639
640 if (!isatty(fd))
641 was_echo = -1;
642 else {
643 ioctl(fd, TIOCGETP, &ttyparams);
644 was_echo = (ttyparams.sg_flags & ECHO) != 0;
645 if (echo)
646 ttyparams.sg_flags = ttyparams.sg_flags | ECHO;
647 else
648 ttyparams.sg_flags = ttyparams.sg_flags & ~ECHO;
649 ioctl(fd, TIOCSETP, &ttyparams);
650 }
651
652 return (was_echo);
653
654} /* end snmp_ttyecho() */
655#endif /* HAVE_TCGETATTR */
656#endif /* HAVE_GETPASS */
657
658
659
660
661/*******************************************************************-o-******
662 * snmp_getpassphrase
663 *
664 * Parameters:
665 * *prompt (May be NULL.)
Michael Slifcak2ace8e71999-05-14 16:47:10 +0000666 * bvisible TRUE means echo back user input.
Michael Slifcak59d6b351999-04-07 19:23:22 +0000667 *
668 * Returns:
669 * Pointer to newly allocated, null terminated string containing
670 * passphrase -OR-
671 * NULL on error.
672 *
673 *
674 * Prompt stdin for a string (or passphrase). Return a copy of the
675 * input in a null terminated string.
676 *
677 * FIX Put HAVE_GETPASS in autoconf.
678 */
679char *
Michael Slifcak2ace8e71999-05-14 16:47:10 +0000680snmp_getpassphrase(const char *prompt, int bvisible)
Michael Slifcak59d6b351999-04-07 19:23:22 +0000681{
Niels Baggesen0045e2f1999-05-03 22:40:11 +0000682 int ti = 0;
683 size_t len;
Michael Slifcak59d6b351999-04-07 19:23:22 +0000684
685 char *bufp = NULL;
686 static char buffer[SNMP_MAXBUF];
687
688 FILE *ofp = stdout;
689
690
691 /*
692 * Query stdin for a passphrase.
693 */
694#ifdef HAVE_GETPASS
695 if ( isatty(0) ) {
696 return getpass( (prompt) ? prompt : "" );
697 }
698#endif
699
700 fputs( (prompt) ? prompt : "", ofp );
701
Michael Slifcak2ace8e71999-05-14 16:47:10 +0000702 if ( !bvisible ) {
Michael Slifcak59d6b351999-04-07 19:23:22 +0000703 ti = snmp_ttyecho(0, 0);
704 }
705
706 fgets(buffer, sizeof(buffer), stdin);
707
Michael Slifcak2ace8e71999-05-14 16:47:10 +0000708 if ( !bvisible ) {
Michael Slifcak59d6b351999-04-07 19:23:22 +0000709 ti = snmp_ttyecho(0, ti);
710 fputs( "\n", ofp );
711 }
712
713
714 /*
715 * Copy the input and zero out the read-in buffer.
716 */
717 len = strlen(buffer);
718 if ( buffer[len-1] == '\n' ) buffer[--len] = '\0';
719
Michael Slifcakafb22b81999-11-05 14:22:52 +0000720 bufp = (char *)calloc(1,len+1);
Michael Slifcak59d6b351999-04-07 19:23:22 +0000721 memcpy(bufp, buffer, len+1);
722
723 SNMP_ZERO(buffer, SNMP_MAXBUF);
724
725
726 return bufp;
727
728} /* end snmp_getpassphrase() */
729
Michael Slifcakd3d86411999-07-27 19:24:03 +0000730#ifdef WIN32
731
732int snmp_ttyecho(const int fd, const int echo) { return 0; }
733
734/*
735 * stops at the first newline, carrier return, or backspace.
736 * WARNING! _getch does NOT read <Ctrl-C>
737 */
738char *getpass( const char * prompt )
739{
740 static char pbuf[128];
741 int ch, lim;
742
743 _cputs(prompt);
744 for (ch=0, lim=0; ch != '\n' && lim < sizeof(pbuf); )
745 {
746 ch = _getch(); /* look ma, no echo ! */
747 if (ch == '\r' || ch == '\n' || ch == '\b')
748 break;
749 pbuf[lim++] = ch;
750 }
751 pbuf[lim] = '\0';
752 puts("\n");
753
754 return pbuf;
755}
756#endif /* WIN32 */
757