Blame apps/encode_keychange.c

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