792 lines
21 KiB
C
792 lines
21 KiB
C
|
/*
|
||
|
* encode_keychange.c
|
||
|
*
|
||
|
* Collect information to build a KeyChange encoding, per the textual
|
||
|
* convention given in RFC 2274, Section 5. Compute the value and
|
||
|
* dump to stdout as a string of hex nibbles.
|
||
|
*
|
||
|
*
|
||
|
* Passphrase material may come from many sources. The following are
|
||
|
* checked in order (see get_user_passphrases()):
|
||
|
* - Prompt always if -f is given.
|
||
|
* - Commandline arguments.
|
||
|
* - PASSPHRASE_FILE.
|
||
|
* - Prompts on stdout. Use -P to turn off prompt tags.
|
||
|
*
|
||
|
*
|
||
|
* FIX Better name?
|
||
|
* FIX Change encode_keychange() to take random bits?
|
||
|
* FIX QUITFUN not quite appropriate here...
|
||
|
* FIX This is slow...
|
||
|
*/
|
||
|
|
||
|
#include <net-snmp/net-snmp-config.h>
|
||
|
|
||
|
#include <stdio.h>
|
||
|
#include <ctype.h>
|
||
|
#include <sys/types.h>
|
||
|
#include <sys/stat.h>
|
||
|
#if HAVE_UNISTD_H
|
||
|
#include <unistd.h>
|
||
|
#endif
|
||
|
#if HAVE_STRING_H
|
||
|
#include <string.h>
|
||
|
#else
|
||
|
#include <strings.h>
|
||
|
#endif
|
||
|
#ifdef HAVE_NETINET_IN_H
|
||
|
#include <netinet/in.h>
|
||
|
#endif
|
||
|
|
||
|
#include <net-snmp/net-snmp-includes.h>
|
||
|
|
||
|
#include <stdlib.h>
|
||
|
|
||
|
/*
|
||
|
* Globals, &c...
|
||
|
*/
|
||
|
char *local_progname;
|
||
|
char *local_passphrase_filename;
|
||
|
|
||
|
#define NL "\n"
|
||
|
|
||
|
#define USAGE "Usage: %s [-fhPvV] -t (md5|sha1) [-O \"<old_passphrase>\"][-N \"<new_passphrase>\"][-E [0x]<engineID>]"
|
||
|
|
||
|
#define OPTIONLIST "E:fhN:O:Pt:vVD"
|
||
|
|
||
|
#define PASSPHRASE_DIR ".snmp"
|
||
|
/*
|
||
|
* Rooted at $HOME.
|
||
|
*/
|
||
|
#define PASSPHRASE_FILE "passphrase.ek"
|
||
|
/*
|
||
|
* Format: two lines containing old and new passphrases, nothing more.
|
||
|
*
|
||
|
* XXX Add creature comforts like: comments and
|
||
|
* tokens identifying passphrases, separate directory check,
|
||
|
* check in current directory (?), traverse a path of
|
||
|
* directories (?)...
|
||
|
* FIX Better name?
|
||
|
*/
|
||
|
|
||
|
|
||
|
int forcepassphrase = 0, /* Always prompt for passphrases. */
|
||
|
promptindicator = 1, /* Output an indicator that input
|
||
|
* is requested. */
|
||
|
visible = 0, /* Echo passphrases to terminal. */
|
||
|
verbose = 0; /* Output progress to stderr. */
|
||
|
size_t engineid_len = 0;
|
||
|
|
||
|
u_char *engineid = NULL; /* Both input & final binary form. */
|
||
|
char *newpass = NULL, *oldpass = NULL;
|
||
|
|
||
|
char *transform_type_input = NULL;
|
||
|
|
||
|
const oid *transform_type = NULL; /* Type of HMAC hash to use. */
|
||
|
size_t transform_type_len = 0;
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Prototypes.
|
||
|
*/
|
||
|
void usage_to_file(FILE * ofp);
|
||
|
void usage_synopsis(FILE * ofp);
|
||
|
int get_user_passphrases(void);
|
||
|
int snmp_ttyecho(const int fd, const int echo);
|
||
|
char *snmp_getpassphrase(const char *prompt, int fvisible);
|
||
|
|
||
|
#ifdef WIN32
|
||
|
#define HAVE_GETPASS 1
|
||
|
char *getpass(const char *prompt);
|
||
|
int isatty(int);
|
||
|
int _cputs(const char *);
|
||
|
int _getch(void);
|
||
|
#endif
|
||
|
|
||
|
/*******************************************************************-o-******
|
||
|
*/
|
||
|
int
|
||
|
main(int argc, char **argv)
|
||
|
{
|
||
|
int rval = 1;
|
||
|
size_t oldKu_len = SNMP_MAXBUF_SMALL,
|
||
|
newKu_len = SNMP_MAXBUF_SMALL,
|
||
|
oldkul_len = SNMP_MAXBUF_SMALL,
|
||
|
newkul_len = SNMP_MAXBUF_SMALL, keychange_len = SNMP_MAXBUF_SMALL;
|
||
|
|
||
|
char *s = NULL;
|
||
|
u_char oldKu[SNMP_MAXBUF_SMALL],
|
||
|
newKu[SNMP_MAXBUF_SMALL],
|
||
|
oldkul[SNMP_MAXBUF_SMALL],
|
||
|
newkul[SNMP_MAXBUF_SMALL], keychange[SNMP_MAXBUF_SMALL];
|
||
|
|
||
|
int i, auth_type;
|
||
|
int arg = 1;
|
||
|
|
||
|
local_progname = argv[0];
|
||
|
local_passphrase_filename = (char *) malloc(sizeof(PASSPHRASE_DIR) +
|
||
|
sizeof(PASSPHRASE_FILE) +
|
||
|
4);
|
||
|
if (!local_passphrase_filename) {
|
||
|
fprintf(stderr, "%s: out of memory!", local_progname);
|
||
|
exit(-1);
|
||
|
}
|
||
|
sprintf(local_passphrase_filename, "%s/%s", PASSPHRASE_DIR,
|
||
|
PASSPHRASE_FILE);
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Parse.
|
||
|
*/
|
||
|
for (; (arg < argc) && (argv[arg][0] == '-'); arg++) {
|
||
|
switch (argv[arg][1]) {
|
||
|
case 'D':
|
||
|
snmp_set_do_debugging(1);
|
||
|
break;
|
||
|
case 'E':
|
||
|
engineid = (u_char *) argv[++arg];
|
||
|
break;
|
||
|
case 'f':
|
||
|
forcepassphrase = 1;
|
||
|
break;
|
||
|
case 'N':
|
||
|
newpass = argv[++arg];
|
||
|
break;
|
||
|
case 'O':
|
||
|
oldpass = argv[++arg];
|
||
|
break;
|
||
|
case 'P':
|
||
|
promptindicator = 0;
|
||
|
break;
|
||
|
case 't':
|
||
|
transform_type_input = argv[++arg];
|
||
|
break;
|
||
|
case 'v':
|
||
|
verbose = 1;
|
||
|
break;
|
||
|
case 'V':
|
||
|
visible = 1;
|
||
|
break;
|
||
|
case 'h':
|
||
|
rval = 0;
|
||
|
/* fallthrough */
|
||
|
default:
|
||
|
usage_to_file(stdout);
|
||
|
exit(rval);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!transform_type_input) {
|
||
|
fprintf(stderr, "The -t option is mandatory.\n");
|
||
|
usage_synopsis(stdout);
|
||
|
exit(1000);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Convert and error check transform_type.
|
||
|
*/
|
||
|
auth_type = usm_lookup_auth_type(transform_type_input);
|
||
|
transform_type = sc_get_auth_oid( auth_type, &transform_type_len );
|
||
|
if (NULL == transform_type) {
|
||
|
fprintf(stderr,
|
||
|
"Unrecognized hash transform: \"%s\".\n",
|
||
|
transform_type_input);
|
||
|
usage_synopsis(stderr);
|
||
|
QUITFUN(SNMPERR_GENERR, main_quit);
|
||
|
}
|
||
|
|
||
|
if (verbose) {
|
||
|
fprintf(stderr, "Hash:\t\t%s\n", sc_get_auth_name(auth_type));
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Build engineID. Accept hex engineID as the bits
|
||
|
* "in-and-of-themselves", otherwise create an engineID with the
|
||
|
* given string as text.
|
||
|
*
|
||
|
* If no engineID is given, lookup the first IP address for the
|
||
|
* localhost and use that (see setup_engineID()).
|
||
|
*/
|
||
|
if (engineid && (tolower(*(engineid + 1)) == 'x')) {
|
||
|
engineid_len = hex_to_binary2(engineid + 2,
|
||
|
strlen((char *) engineid) - 2,
|
||
|
(char **) &engineid);
|
||
|
DEBUGMSGTL(("encode_keychange", "engineIDLen: %lu\n",
|
||
|
(unsigned long)engineid_len));
|
||
|
} else {
|
||
|
engineid_len = setup_engineID(&engineid, (char *) engineid);
|
||
|
if ((ssize_t)engineid_len < 0)
|
||
|
exit(1);
|
||
|
}
|
||
|
|
||
|
#ifdef NETSNMP_ENABLE_TESTING_CODE
|
||
|
if (verbose) {
|
||
|
fprintf(stderr, "EngineID:\t%s\n",
|
||
|
/*
|
||
|
* XXX =
|
||
|
*/ dump_snmpEngineID(engineid, &engineid_len));
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Get passphrases from user.
|
||
|
*/
|
||
|
rval = get_user_passphrases();
|
||
|
QUITFUN(rval, main_quit);
|
||
|
|
||
|
if (strlen(oldpass) < USM_LENGTH_P_MIN) {
|
||
|
fprintf(stderr, "Old passphrase must be greater than %d "
|
||
|
"characters in length.\n", USM_LENGTH_P_MIN);
|
||
|
QUITFUN(SNMPERR_GENERR, main_quit);
|
||
|
|
||
|
} else if (strlen(newpass) < USM_LENGTH_P_MIN) {
|
||
|
fprintf(stderr, "New passphrase must be greater than %d "
|
||
|
"characters in length.\n", USM_LENGTH_P_MIN);
|
||
|
QUITFUN(SNMPERR_GENERR, main_quit);
|
||
|
}
|
||
|
|
||
|
if (verbose) {
|
||
|
fprintf(stderr,
|
||
|
"Old passphrase:\t%s\nNew passphrase:\t%s\n",
|
||
|
oldpass, newpass);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Compute Ku and Kul's from old and new passphrases, then
|
||
|
* compute the keychange string & print it out.
|
||
|
*/
|
||
|
rval = sc_init();
|
||
|
QUITFUN(rval, main_quit);
|
||
|
|
||
|
|
||
|
rval = generate_Ku(transform_type, transform_type_len,
|
||
|
(u_char *) oldpass, strlen(oldpass),
|
||
|
oldKu, &oldKu_len);
|
||
|
QUITFUN(rval, main_quit);
|
||
|
|
||
|
|
||
|
rval = generate_Ku(transform_type, transform_type_len,
|
||
|
(u_char *) newpass, strlen(newpass),
|
||
|
newKu, &newKu_len);
|
||
|
QUITFUN(rval, main_quit);
|
||
|
|
||
|
|
||
|
DEBUGMSGTL(("encode_keychange", "EID (%lu): ", (unsigned long)engineid_len));
|
||
|
for (i = 0; i < (int) engineid_len; i++)
|
||
|
DEBUGMSGTL(("encode_keychange", "%02x", (int) (engineid[i])));
|
||
|
DEBUGMSGTL(("encode_keychange", "\n"));
|
||
|
|
||
|
DEBUGMSGTL(("encode_keychange", "old Ku (%lu) (from %s): ", (unsigned long)oldKu_len,
|
||
|
oldpass));
|
||
|
for (i = 0; i < (int) oldKu_len; i++)
|
||
|
DEBUGMSGTL(("encode_keychange", "%02x", (int) (oldKu[i])));
|
||
|
DEBUGMSGTL(("encode_keychange", "\n"));
|
||
|
|
||
|
rval = generate_kul(transform_type, transform_type_len,
|
||
|
engineid, engineid_len,
|
||
|
oldKu, oldKu_len, oldkul, &oldkul_len);
|
||
|
QUITFUN(rval, main_quit);
|
||
|
|
||
|
|
||
|
DEBUGMSGTL(("encode_keychange", "generating old Kul (%lu) (from Ku): ",
|
||
|
(unsigned long)oldkul_len));
|
||
|
for (i = 0; i < (int) oldkul_len; i++)
|
||
|
DEBUGMSGTL(("encode_keychange", "%02x", (int) (oldkul[i])));
|
||
|
DEBUGMSGTL(("encode_keychange", "\n"));
|
||
|
|
||
|
rval = generate_kul(transform_type, transform_type_len,
|
||
|
engineid, engineid_len,
|
||
|
newKu, newKu_len, newkul, &newkul_len);
|
||
|
QUITFUN(rval, main_quit);
|
||
|
|
||
|
DEBUGMSGTL(("encode_keychange", "generating new Kul (%lu) (from Ku): ",
|
||
|
(unsigned long)oldkul_len));
|
||
|
for (i = 0; i < (int) newkul_len; i++)
|
||
|
DEBUGMSGTL(("encode_keychange", "%02x", newkul[i]));
|
||
|
DEBUGMSGTL(("encode_keychange", "\n"));
|
||
|
|
||
|
rval = encode_keychange(transform_type, transform_type_len,
|
||
|
oldkul, oldkul_len,
|
||
|
newkul, newkul_len, keychange, &keychange_len);
|
||
|
QUITFUN(rval, main_quit);
|
||
|
|
||
|
|
||
|
|
||
|
binary_to_hex(keychange, keychange_len, &s);
|
||
|
printf("%s%s\n", (verbose) ? "KeyChange string:\t" : "", /* XXX stdout */
|
||
|
s);
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Cleanup.
|
||
|
*/
|
||
|
main_quit:
|
||
|
snmp_call_callbacks(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_SHUTDOWN,
|
||
|
NULL);
|
||
|
|
||
|
|
||
|
SNMP_ZERO(oldpass, strlen(oldpass));
|
||
|
SNMP_ZERO(newpass, strlen(newpass));
|
||
|
|
||
|
memset(oldKu, 0, oldKu_len);
|
||
|
memset(newKu, 0, newKu_len);
|
||
|
|
||
|
memset(oldkul, 0, oldkul_len);
|
||
|
memset(newkul, 0, newkul_len);
|
||
|
|
||
|
SNMP_ZERO(s, strlen(s));
|
||
|
|
||
|
return rval;
|
||
|
|
||
|
} /* end main() */
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*******************************************************************-o-******
|
||
|
*/
|
||
|
void
|
||
|
usage_synopsis(FILE * ofp)
|
||
|
{
|
||
|
fprintf(ofp, USAGE "\n\
|
||
|
\n\
|
||
|
-E [0x]<engineID> EngineID used for kul generation.\n\
|
||
|
-f Force passphrases to be read from stdin.\n\
|
||
|
-h Help.\n\
|
||
|
-N \"<new_passphrase>\" Passphrase used to generate new Ku.\n\
|
||
|
-O \"<old_passphrase>\" Passphrase used to generate old Ku.\n\
|
||
|
-P Turn off prompt indicators.\n\
|
||
|
-t md5 | sha1 HMAC hash transform type.\n\
|
||
|
-v Verbose.\n\
|
||
|
-V Visible. Echo passphrases to terminal.\n\
|
||
|
" NL, local_progname);
|
||
|
|
||
|
} /* end usage_synopsis() */
|
||
|
|
||
|
void
|
||
|
usage_to_file(FILE * ofp)
|
||
|
{
|
||
|
char *s;
|
||
|
|
||
|
usage_synopsis(ofp);
|
||
|
|
||
|
fprintf(ofp, "\n%s\
|
||
|
a) Commandline options,\n\
|
||
|
b) The file \"%s/%s\",\n\
|
||
|
c) stdin -or- User input from the terminal.\n\n%s\
|
||
|
" NL,
|
||
|
"Only -t is mandatory. The transform is used to convert P=>Ku, convert\n\
|
||
|
Ku=>Kul, and to hash the old Kul with the random bits.\n\
|
||
|
\n\
|
||
|
Passphrase will be taken from the first successful source as follows:\n",
|
||
|
(s = getenv("HOME")) ? s : "$HOME", local_passphrase_filename,
|
||
|
"-f will require reading from the stdin/terminal, ignoring a) and b).\n\
|
||
|
-P will prevent prompts for passphrases to stdout from being printed.\n\
|
||
|
\n\
|
||
|
<engineID> is interpreted as a hex string when preceded by \"0x\",\n\
|
||
|
otherwise it is created to contain \"text\". If nothing is given,\n\
|
||
|
<engineID> is constructed from the first IP address for the local host.\n");
|
||
|
|
||
|
|
||
|
/*
|
||
|
* FIX -- make this possible?
|
||
|
* -r [0x]<random_bits> Random bits used in KeyChange XOR.
|
||
|
*
|
||
|
* <engineID> and <random_bits> are interpreted as hex strings when
|
||
|
* preceeded by \"0x\", otherwise <engineID> is created to contain \"text\"
|
||
|
* and <random_bits> are the same as the ascii input.
|
||
|
*
|
||
|
* <random_bits> will be generated by SCAPI if not given. If value is
|
||
|
* too long, it will be truncated; if too short, the remainder will be
|
||
|
* filled in with zeros.
|
||
|
*/
|
||
|
|
||
|
} /* end usage() */
|
||
|
|
||
|
|
||
|
/*
|
||
|
* this defined for HPUX aCC because the aCC doesn't drop the
|
||
|
*/
|
||
|
/*
|
||
|
* snmp_parse_args.c functionality if compile with -g, PKY
|
||
|
*/
|
||
|
|
||
|
void
|
||
|
usage(void)
|
||
|
{
|
||
|
usage_to_file(stdout);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*******************************************************************-o-******
|
||
|
* get_user_passphrases
|
||
|
*
|
||
|
* Returns:
|
||
|
* SNMPERR_SUCCESS Success.
|
||
|
* SNMPERR_GENERR Otherwise.
|
||
|
*
|
||
|
*
|
||
|
* Acquire new and old passphrases from the user:
|
||
|
*
|
||
|
* + Always prompt if 'forcepassphrase' is set.
|
||
|
* + Use given arguments if they are defined.
|
||
|
* + Otherwise read file format from PASSPHRASE_FILE.
|
||
|
* Sanity check existence and permissions of the path.
|
||
|
* ASSUME for now that PASSPHRASE_FILE is rooted only at $HOME.
|
||
|
* + Otherwise prompt user for passphrase(s).
|
||
|
* Echo input if 'visible' is set.
|
||
|
* Turning off 'promptindicator' makes piping in input cleaner.
|
||
|
*
|
||
|
* NOTE Only using forcepassphrase mandates taking both passphrases
|
||
|
* from the same source. Otherwise processing continues until both
|
||
|
* passphrases are defined.
|
||
|
*/
|
||
|
int
|
||
|
get_user_passphrases(void)
|
||
|
{
|
||
|
int rval = SNMPERR_SUCCESS;
|
||
|
size_t len;
|
||
|
|
||
|
char *obuf = NULL, *nbuf = NULL;
|
||
|
|
||
|
char path[SNMP_MAXBUF], buf[SNMP_MAXBUF], *s = NULL;
|
||
|
|
||
|
struct stat statbuf;
|
||
|
FILE *fp = NULL;
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Allow prompts to the user to override all other sources.
|
||
|
* Nothing to do otherwise if oldpass and newpass are already defined.
|
||
|
*/
|
||
|
if (forcepassphrase)
|
||
|
goto get_user_passphrases_prompt;
|
||
|
if (oldpass && newpass)
|
||
|
goto get_user_passphrases_quit;
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Read passphrases out of PASSPHRASE_FILE. Sanity check the
|
||
|
* path for existence and access first. Refuse to read
|
||
|
* if the permissions are wrong.
|
||
|
*/
|
||
|
s = getenv("HOME");
|
||
|
snprintf(path, sizeof(path), "%s/%s", s, PASSPHRASE_DIR);
|
||
|
path[ sizeof(path)-1 ] = 0;
|
||
|
|
||
|
/*
|
||
|
* Test directory.
|
||
|
*/
|
||
|
if (stat(path, &statbuf) < 0) {
|
||
|
fprintf(stderr, "Cannot access directory \"%s\".\n", path);
|
||
|
QUITFUN(SNMPERR_GENERR, get_user_passphrases_quit);
|
||
|
#ifndef WIN32
|
||
|
} else if (statbuf.st_mode & (S_IRWXG | S_IRWXO)) {
|
||
|
fprintf(stderr,
|
||
|
"Directory \"%s\" is accessible by group or world.\n",
|
||
|
path);
|
||
|
QUITFUN(SNMPERR_GENERR, get_user_passphrases_quit);
|
||
|
#endif /* !WIN32 */
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Test file.
|
||
|
*/
|
||
|
snprintf(path, sizeof(path), "%s/%s", s, local_passphrase_filename);
|
||
|
path[ sizeof(path)-1 ] = 0;
|
||
|
if (stat(path, &statbuf) < 0) {
|
||
|
fprintf(stderr, "Cannot access file \"%s\".\n", path);
|
||
|
QUITFUN(SNMPERR_GENERR, get_user_passphrases_quit);
|
||
|
#ifndef WIN32
|
||
|
} else if (statbuf.st_mode & (S_IRWXG | S_IRWXO)) {
|
||
|
fprintf(stderr,
|
||
|
"File \"%s\" is accessible by group or world.\n", path);
|
||
|
QUITFUN(SNMPERR_GENERR, get_user_passphrases_quit);
|
||
|
#endif /* !WIN32 */
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Open the file.
|
||
|
*/
|
||
|
if ((fp = fopen(path, "r")) == NULL) {
|
||
|
fprintf(stderr, "Cannot open \"%s\".", path);
|
||
|
QUITFUN(SNMPERR_GENERR, get_user_passphrases_quit);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Read 1st line.
|
||
|
*/
|
||
|
if (!fgets(buf, sizeof(buf), fp)) {
|
||
|
if (verbose) {
|
||
|
fprintf(stderr, "Passphrase file \"%s\" is empty...\n", path);
|
||
|
}
|
||
|
goto get_user_passphrases_prompt;
|
||
|
|
||
|
} else if (!oldpass) {
|
||
|
len = strlen(buf);
|
||
|
if (buf[len - 1] == '\n')
|
||
|
buf[--len] = '\0';
|
||
|
oldpass = (char *) calloc(1, len + 1);
|
||
|
if (oldpass)
|
||
|
memcpy(oldpass, buf, len + 1);
|
||
|
}
|
||
|
/*
|
||
|
* Read 2nd line.
|
||
|
*/
|
||
|
if (!fgets(buf, sizeof(buf), fp)) {
|
||
|
if (verbose) {
|
||
|
fprintf(stderr, "Only one line in file \"%s\"...\n", path);
|
||
|
}
|
||
|
|
||
|
} else if (!newpass) {
|
||
|
len = strlen(buf);
|
||
|
if (buf[len - 1] == '\n')
|
||
|
buf[--len] = '\0';
|
||
|
newpass = (char *) calloc(1, len + 1);
|
||
|
if (newpass)
|
||
|
memcpy(newpass, buf, len + 1);
|
||
|
}
|
||
|
|
||
|
if (oldpass && newpass)
|
||
|
goto get_user_passphrases_quit;
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Prompt the user for passphrase entry. Visible prompts
|
||
|
* may be omitted, and invisible entry may turned off.
|
||
|
*/
|
||
|
get_user_passphrases_prompt:
|
||
|
if (forcepassphrase) {
|
||
|
oldpass = newpass = NULL;
|
||
|
}
|
||
|
|
||
|
if (!oldpass) {
|
||
|
oldpass = obuf
|
||
|
= snmp_getpassphrase((promptindicator) ? "Old passphrase: " :
|
||
|
"", visible);
|
||
|
}
|
||
|
if (!newpass) {
|
||
|
newpass = nbuf
|
||
|
= snmp_getpassphrase((promptindicator) ? "New passphrase: " :
|
||
|
"", visible);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Check that both passphrases were defined.
|
||
|
*/
|
||
|
if (oldpass && newpass) {
|
||
|
goto get_user_passphrases_quit;
|
||
|
} else {
|
||
|
rval = SNMPERR_GENERR;
|
||
|
}
|
||
|
|
||
|
|
||
|
get_user_passphrases_quit:
|
||
|
memset(buf, 0, SNMP_MAXBUF);
|
||
|
|
||
|
if (obuf != oldpass) {
|
||
|
SNMP_ZERO(obuf, strlen(obuf));
|
||
|
SNMP_FREE(obuf);
|
||
|
}
|
||
|
if (nbuf != newpass) {
|
||
|
SNMP_ZERO(nbuf, strlen(nbuf));
|
||
|
SNMP_FREE(nbuf);
|
||
|
}
|
||
|
|
||
|
if (fp)
|
||
|
fclose (fp);
|
||
|
|
||
|
return rval;
|
||
|
|
||
|
} /* end get_user_passphrases() */
|
||
|
|
||
|
/*******************************************************************-o-******
|
||
|
* snmp_ttyecho
|
||
|
*
|
||
|
* Parameters:
|
||
|
* fd Descriptor of terminal on which to toggle echoing.
|
||
|
* echo TRUE if echoing should be on; FALSE otherwise.
|
||
|
*
|
||
|
* Returns:
|
||
|
* Previous value of echo setting.
|
||
|
*
|
||
|
*
|
||
|
* FIX Put HAVE_TCGETATTR in autoconf?
|
||
|
*/
|
||
|
#ifndef HAVE_GETPASS
|
||
|
#ifdef HAVE_TCGETATTR
|
||
|
#include <termios.h>
|
||
|
int
|
||
|
snmp_ttyecho(const int fd, const int echo)
|
||
|
{
|
||
|
struct termios tio;
|
||
|
int was_echo;
|
||
|
|
||
|
|
||
|
if (!isatty(fd))
|
||
|
return (-1);
|
||
|
tcgetattr(fd, &tio);
|
||
|
was_echo = (tio.c_lflag & ECHO) != 0;
|
||
|
if (echo)
|
||
|
tio.c_lflag |= (ECHO | ECHONL);
|
||
|
else
|
||
|
tio.c_lflag &= ~(ECHO | ECHONL);
|
||
|
tcsetattr(fd, TCSANOW, &tio);
|
||
|
|
||
|
return (was_echo);
|
||
|
|
||
|
} /* end snmp_ttyecho() */
|
||
|
|
||
|
#else
|
||
|
#include <sgtty.h>
|
||
|
int
|
||
|
snmp_ttyecho(const int fd, const int echo)
|
||
|
{
|
||
|
struct sgttyb ttyparams;
|
||
|
int was_echo;
|
||
|
|
||
|
|
||
|
if (!isatty(fd))
|
||
|
was_echo = -1;
|
||
|
else {
|
||
|
ioctl(fd, TIOCGETP, &ttyparams);
|
||
|
was_echo = (ttyparams.sg_flags & ECHO) != 0;
|
||
|
if (echo)
|
||
|
ttyparams.sg_flags = ttyparams.sg_flags | ECHO;
|
||
|
else
|
||
|
ttyparams.sg_flags = ttyparams.sg_flags & ~ECHO;
|
||
|
ioctl(fd, TIOCSETP, &ttyparams);
|
||
|
}
|
||
|
|
||
|
return (was_echo);
|
||
|
|
||
|
} /* end snmp_ttyecho() */
|
||
|
#endif /* HAVE_TCGETATTR */
|
||
|
#endif /* HAVE_GETPASS */
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*******************************************************************-o-******
|
||
|
* snmp_getpassphrase
|
||
|
*
|
||
|
* Parameters:
|
||
|
* *prompt (May be NULL.)
|
||
|
* bvisible TRUE means echo back user input.
|
||
|
*
|
||
|
* Returns:
|
||
|
* Pointer to newly allocated, null terminated string containing
|
||
|
* passphrase -OR-
|
||
|
* NULL on error.
|
||
|
*
|
||
|
*
|
||
|
* Prompt stdin for a string (or passphrase). Return a copy of the
|
||
|
* input in a null terminated string.
|
||
|
*
|
||
|
* FIX Put HAVE_GETPASS in autoconf.
|
||
|
*/
|
||
|
char *
|
||
|
snmp_getpassphrase(const char *prompt, int bvisible)
|
||
|
{
|
||
|
int ti = 0;
|
||
|
size_t len;
|
||
|
|
||
|
char *bufp = NULL;
|
||
|
static char buffer[SNMP_MAXBUF];
|
||
|
|
||
|
FILE *ofp = stdout;
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Query stdin for a passphrase.
|
||
|
*/
|
||
|
#ifdef HAVE_GETPASS
|
||
|
if (isatty(0)) {
|
||
|
return getpass((prompt) ? prompt : "");
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
fputs((prompt) ? prompt : "", ofp);
|
||
|
|
||
|
if (!bvisible) {
|
||
|
ti = snmp_ttyecho(0, 0);
|
||
|
}
|
||
|
|
||
|
bufp = fgets(buffer, sizeof(buffer), stdin);
|
||
|
|
||
|
if (!bvisible) {
|
||
|
ti = snmp_ttyecho(0, ti);
|
||
|
fputs("\n", ofp);
|
||
|
}
|
||
|
if (!bufp) {
|
||
|
fprintf(stderr, "Aborted...\n");
|
||
|
exit(1);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Copy the input and zero out the read-in buffer.
|
||
|
*/
|
||
|
len = strlen(buffer);
|
||
|
if (buffer[len - 1] == '\n')
|
||
|
buffer[--len] = '\0';
|
||
|
|
||
|
bufp = (char *) calloc(1, len + 1);
|
||
|
if (bufp)
|
||
|
memcpy(bufp, buffer, len + 1);
|
||
|
|
||
|
memset(buffer, 0, SNMP_MAXBUF);
|
||
|
|
||
|
|
||
|
return bufp;
|
||
|
|
||
|
} /* end snmp_getpassphrase() */
|
||
|
|
||
|
#ifdef WIN32
|
||
|
|
||
|
int
|
||
|
snmp_ttyecho(const int fd, const int echo)
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* stops at the first newline, carrier return, or backspace.
|
||
|
* WARNING! _getch does NOT read <Ctrl-C>
|
||
|
*/
|
||
|
char *
|
||
|
getpass(const char *prompt)
|
||
|
{
|
||
|
static char pbuf[128];
|
||
|
int ch, lim;
|
||
|
|
||
|
_cputs(prompt);
|
||
|
for (ch = 0, lim = 0; ch != '\n' && lim < sizeof(pbuf)-1;) {
|
||
|
ch = _getch(); /* look ma, no echo ! */
|
||
|
if (ch == '\r' || ch == '\n' || ch == '\b')
|
||
|
break;
|
||
|
pbuf[lim++] = ch;
|
||
|
}
|
||
|
pbuf[lim] = '\0';
|
||
|
puts("\n");
|
||
|
|
||
|
return pbuf;
|
||
|
}
|
||
|
#endif /* WIN32 */
|