encode_keychange.c
上传用户:wxp200602
上传日期:2007-10-30
资源大小:4028k
文件大小:21k
- /*
- * 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
- #if HAVE_WINSOCK_H
- #include <winsock.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. */
- /*
- * 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 = SNMPERR_SUCCESS;
- 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;
- 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;
- 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.
- */
- #ifndef DISABLE_MD5
- if (!strcmp(transform_type_input, "md5")) {
- transform_type = usmHMACMD5AuthProtocol;
- } else
- #endif
- if (!strcmp(transform_type_input, "sha1")) {
- transform_type = usmHMACSHA1AuthProtocol;
- } else {
- fprintf(stderr,
- "Unrecognized hash transform: "%s".n",
- transform_type_input);
- usage_synopsis(stderr);
- QUITFUN(rval = SNMPERR_GENERR, main_quit);
- }
- if (verbose) {
- fprintf(stderr, "Hash:tt%sn",
- #ifndef DISABLE_MD5
- (transform_type == usmHMACMD5AuthProtocol)
- ? "usmHMACMD5AuthProtocol" :
- #endif
- "usmHMACSHA1AuthProtocol"
- );
- }
- /*
- * 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: %dn",
- engineid_len));
- } else {
- engineid_len = setup_engineID(&engineid, (char *) engineid);
- }
- #ifdef SNMP_TESTING_CODE
- if (verbose) {
- fprintf(stderr, "EngineID:t%sn",
- /*
- * 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(rval = 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(rval = SNMPERR_GENERR, main_quit);
- }
- if (verbose) {
- fprintf(stderr,
- "Old passphrase:t%snNew passphrase:t%sn",
- 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, USM_LENGTH_OID_TRANSFORM,
- (u_char *) oldpass, strlen(oldpass),
- oldKu, &oldKu_len);
- QUITFUN(rval, main_quit);
- rval = generate_Ku(transform_type, USM_LENGTH_OID_TRANSFORM,
- (u_char *) newpass, strlen(newpass),
- newKu, &newKu_len);
- QUITFUN(rval, main_quit);
- DEBUGMSGTL(("encode_keychange", "EID (%d): ", 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 (%d) (from %s): ", 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, USM_LENGTH_OID_TRANSFORM,
- engineid, engineid_len,
- oldKu, oldKu_len, oldkul, &oldkul_len);
- QUITFUN(rval, main_quit);
- DEBUGMSGTL(("encode_keychange", "generating old Kul (%d) (from Ku): ",
- 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, USM_LENGTH_OID_TRANSFORM,
- engineid, engineid_len,
- newKu, newKu_len, newkul, &newkul_len);
- QUITFUN(rval, main_quit);
- DEBUGMSGTL(("encode_keychange", "generating new Kul (%d) (from Ku): ",
- 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, USM_LENGTH_OID_TRANSFORM,
- oldkul, oldkul_len,
- newkul, newkul_len, keychange, &keychange_len);
- QUITFUN(rval, main_quit);
- binary_to_hex(keychange, keychange_len, &s);
- printf("%s%sn", (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));
- SNMP_ZERO(oldKu, oldKu_len);
- SNMP_ZERO(newKu, newKu_len);
- SNMP_ZERO(oldkul, oldkul_len);
- SNMP_ZERO(newkul, 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
- Only -t is mandatory. The transform is used to convert P=>Ku, convertn
- 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
- a) Commandline options,n
- b) The file "%s/%s",n
- c) stdin -or- User input from the terminal.n
- n
- -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 intepreted as a hex string when preceeded 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
- " NL, (s = getenv("HOME")) ? s : "$HOME", local_passphrase_filename);
- /*
- * FIX -- make this possible?
- * -r [0x]<random_bits> Random bits used in KeyChange XOR.
- *
- * <engineID> and <random_bits> are intepreted 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;
- /*
- * 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(rval = 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(rval = 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(rval = 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(rval = SNMPERR_GENERR, get_user_passphrases_quit);
- #endif /* !WIN32 */
- }
- /*
- * Open the file.
- */
- if ((fp = fopen(path, "r")) == NULL) {
- fprintf(stderr, "Cannot open "%s".", path);
- QUITFUN(rval = 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] = ' ';
- 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] = ' ';
- 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:
- SNMP_ZERO(buf, SNMP_MAXBUF);
- if (obuf != oldpass) {
- SNMP_ZERO(obuf, strlen(obuf));
- SNMP_FREE(obuf);
- }
- if (nbuf != newpass) {
- SNMP_ZERO(nbuf, strlen(nbuf));
- SNMP_FREE(nbuf);
- }
- 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);
- }
- fgets(buffer, sizeof(buffer), stdin);
- if (!bvisible) {
- ti = snmp_ttyecho(0, ti);
- fputs("n", ofp);
- }
- /*
- * Copy the input and zero out the read-in buffer.
- */
- len = strlen(buffer);
- if (buffer[len - 1] == 'n')
- buffer[--len] = ' ';
- bufp = (char *) calloc(1, len + 1);
- if (bufp)
- memcpy(bufp, buffer, len + 1);
- SNMP_ZERO(buffer, 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] = ' ';
- puts("n");
- return pbuf;
- }
- #endif /* WIN32 */