encode_keychange.c
上传用户:wxp200602
上传日期:2007-10-30
资源大小:4028k
文件大小:21k
源码类别:

SNMP编程

开发平台:

Unix_Linux

  1. /*
  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. #include <net-snmp/net-snmp-config.h>
  23. #include <stdio.h>
  24. #include <ctype.h>
  25. #include <sys/types.h>
  26. #include <sys/stat.h>
  27. #if HAVE_UNISTD_H
  28. #include <unistd.h>
  29. #endif
  30. #if HAVE_STRING_H
  31. #include <string.h>
  32. #else
  33. #include <strings.h>
  34. #endif
  35. #ifdef HAVE_NETINET_IN_H
  36. #include <netinet/in.h>
  37. #endif
  38. #if HAVE_WINSOCK_H
  39. #include <winsock.h>
  40. #endif
  41. #include <net-snmp/net-snmp-includes.h>
  42. #include <stdlib.h>
  43. /*
  44.  * Globals, &c...
  45.  */
  46. char           *local_progname;
  47. char           *local_passphrase_filename;
  48. #define NL "n"
  49. #define USAGE "Usage: %s [-fhPvV] -t (md5|sha1) [-O "<old_passphrase>"][-N "<new_passphrase>"][-E [0x]<engineID>]"
  50. #define OPTIONLIST "E:fhN:O:Pt:vVD"
  51. #define PASSPHRASE_DIR ".snmp"
  52.         /*
  53.          * Rooted at $HOME.
  54.          */
  55. #define PASSPHRASE_FILE "passphrase.ek"
  56.         /*
  57.          * Format: two lines containing old and new passphrases, nothing more.
  58.          *      
  59.          * XXX  Add creature comforts like: comments and 
  60.          *      tokens identifying passphrases, separate directory check,
  61.          *      check in current directory (?), traverse a path of
  62.          *      directories (?)...
  63.          * FIX  Better name?
  64.          */
  65. int             forcepassphrase = 0,    /* Always prompt for passphrases. */
  66.                 promptindicator = 1,    /* Output an indicator that input
  67.                                          *   is requested.                */
  68.                 visible = 0,    /* Echo passphrases to terminal.  */
  69.                 verbose = 0;    /* Output progress to stderr.     */
  70. size_t          engineid_len = 0;
  71. u_char         *engineid = NULL;        /* Both input & final binary form. */
  72. char           *newpass = NULL, *oldpass = NULL;
  73. char           *transform_type_input = NULL;
  74. const oid      *transform_type = NULL;  /* Type of HMAC hash to use.      */
  75. /*
  76.  * Prototypes.
  77.  */
  78. void            usage_to_file(FILE * ofp);
  79. void            usage_synopsis(FILE * ofp);
  80. int             get_user_passphrases(void);
  81. int             snmp_ttyecho(const int fd, const int echo);
  82. char           *snmp_getpassphrase(const char *prompt, int fvisible);
  83. #ifdef WIN32
  84. #define HAVE_GETPASS 1
  85. char           *getpass(const char *prompt);
  86. int             isatty(int);
  87. int             _cputs(const char *);
  88. int             _getch(void);
  89. #endif
  90. /*******************************************************************-o-******
  91.  */
  92. int
  93. main(int argc, char **argv)
  94. {
  95.     int             rval = SNMPERR_SUCCESS;
  96.     size_t          oldKu_len = SNMP_MAXBUF_SMALL,
  97.         newKu_len = SNMP_MAXBUF_SMALL,
  98.         oldkul_len = SNMP_MAXBUF_SMALL,
  99.         newkul_len = SNMP_MAXBUF_SMALL, keychange_len = SNMP_MAXBUF_SMALL;
  100.     char           *s = NULL;
  101.     u_char          oldKu[SNMP_MAXBUF_SMALL],
  102.         newKu[SNMP_MAXBUF_SMALL],
  103.         oldkul[SNMP_MAXBUF_SMALL],
  104.         newkul[SNMP_MAXBUF_SMALL], keychange[SNMP_MAXBUF_SMALL];
  105.     int             i;
  106.     int             arg = 1;
  107.     local_progname = argv[0];
  108.     local_passphrase_filename = (char *) malloc(sizeof(PASSPHRASE_DIR) +
  109.                                                 sizeof(PASSPHRASE_FILE) +
  110.                                                 4);
  111.     if (!local_passphrase_filename) {
  112.         fprintf(stderr, "%s: out of memory!", local_progname);
  113.         exit(-1);
  114.     }
  115.     sprintf(local_passphrase_filename, "%s/%s", PASSPHRASE_DIR,
  116.             PASSPHRASE_FILE);
  117.     /*
  118.      * Parse.
  119.      */
  120.     for (; (arg < argc) && (argv[arg][0] == '-'); arg++) {
  121.         switch (argv[arg][1]) {
  122.         case 'D':
  123.             snmp_set_do_debugging(1);
  124.             break;
  125.         case 'E':
  126.             engineid = (u_char *) argv[++arg];
  127.             break;
  128.         case 'f':
  129.             forcepassphrase = 1;
  130.             break;
  131.         case 'N':
  132.             newpass = argv[++arg];
  133.             break;
  134.         case 'O':
  135.             oldpass = argv[++arg];
  136.             break;
  137.         case 'P':
  138.             promptindicator = 0;
  139.             break;
  140.         case 't':
  141.             transform_type_input = argv[++arg];
  142.             break;
  143.         case 'v':
  144.             verbose = 1;
  145.             break;
  146.         case 'V':
  147.             visible = 1;
  148.             break;
  149.         case 'h':
  150.             rval = 0;
  151.         default:
  152.             usage_to_file(stdout);
  153.             exit(rval);
  154.         }
  155.     }
  156.     if (!transform_type_input) {
  157.         fprintf(stderr, "The -t option is mandatory.n");
  158.         usage_synopsis(stdout);
  159.         exit(1000);
  160.     }
  161.     /*
  162.      * Convert and error check transform_type.
  163.      */
  164. #ifndef DISABLE_MD5
  165.     if (!strcmp(transform_type_input, "md5")) {
  166.         transform_type = usmHMACMD5AuthProtocol;
  167.     } else
  168. #endif
  169.         if (!strcmp(transform_type_input, "sha1")) {
  170.         transform_type = usmHMACSHA1AuthProtocol;
  171.     } else {
  172.         fprintf(stderr,
  173.                 "Unrecognized hash transform: "%s".n",
  174.                 transform_type_input);
  175.         usage_synopsis(stderr);
  176.         QUITFUN(rval = SNMPERR_GENERR, main_quit);
  177.     }
  178.     if (verbose) {
  179.         fprintf(stderr, "Hash:tt%sn",
  180. #ifndef DISABLE_MD5
  181.                 (transform_type == usmHMACMD5AuthProtocol)
  182.                 ? "usmHMACMD5AuthProtocol" :
  183. #endif
  184.                 "usmHMACSHA1AuthProtocol"
  185.             );
  186.     }
  187.     /*
  188.      * Build engineID.  Accept hex engineID as the bits
  189.      * "in-and-of-themselves", otherwise create an engineID with the
  190.      * given string as text.
  191.      *
  192.      * If no engineID is given, lookup the first IP address for the
  193.      * localhost and use that (see setup_engineID()).
  194.      */
  195.     if (engineid && (tolower(*(engineid + 1)) == 'x')) {
  196.         engineid_len = hex_to_binary2(engineid + 2,
  197.                                       strlen((char *) engineid) - 2,
  198.                                       (char **) &engineid);
  199.         DEBUGMSGTL(("encode_keychange", "engineIDLen: %dn",
  200.                     engineid_len));
  201.     } else {
  202.         engineid_len = setup_engineID(&engineid, (char *) engineid);
  203.     }
  204. #ifdef SNMP_TESTING_CODE
  205.     if (verbose) {
  206.         fprintf(stderr, "EngineID:t%sn",
  207.                 /*
  208.                  * XXX = 
  209.                  */ dump_snmpEngineID(engineid, &engineid_len));
  210.     }
  211. #endif
  212.     /*
  213.      * Get passphrases from user.
  214.      */
  215.     rval = get_user_passphrases();
  216.     QUITFUN(rval, main_quit);
  217.     if (strlen(oldpass) < USM_LENGTH_P_MIN) {
  218.         fprintf(stderr, "Old passphrase must be greater than %d "
  219.                 "characters in length.n", USM_LENGTH_P_MIN);
  220.         QUITFUN(rval = SNMPERR_GENERR, main_quit);
  221.     } else if (strlen(newpass) < USM_LENGTH_P_MIN) {
  222.         fprintf(stderr, "New passphrase must be greater than %d "
  223.                 "characters in length.n", USM_LENGTH_P_MIN);
  224.         QUITFUN(rval = SNMPERR_GENERR, main_quit);
  225.     }
  226.     if (verbose) {
  227.         fprintf(stderr,
  228.                 "Old passphrase:t%snNew passphrase:t%sn",
  229.                 oldpass, newpass);
  230.     }
  231.     /*
  232.      * Compute Ku and Kul's from old and new passphrases, then
  233.      * compute the keychange string & print it out.
  234.      */
  235.     rval = sc_init();
  236.     QUITFUN(rval, main_quit);
  237.     rval = generate_Ku(transform_type, USM_LENGTH_OID_TRANSFORM,
  238.                        (u_char *) oldpass, strlen(oldpass),
  239.                        oldKu, &oldKu_len);
  240.     QUITFUN(rval, main_quit);
  241.     rval = generate_Ku(transform_type, USM_LENGTH_OID_TRANSFORM,
  242.                        (u_char *) newpass, strlen(newpass),
  243.                        newKu, &newKu_len);
  244.     QUITFUN(rval, main_quit);
  245.     DEBUGMSGTL(("encode_keychange", "EID (%d): ", engineid_len));
  246.     for (i = 0; i < (int) engineid_len; i++)
  247.         DEBUGMSGTL(("encode_keychange", "%02x", (int) (engineid[i])));
  248.     DEBUGMSGTL(("encode_keychange", "n"));
  249.     DEBUGMSGTL(("encode_keychange", "old Ku (%d) (from %s): ", oldKu_len,
  250.                 oldpass));
  251.     for (i = 0; i < (int) oldKu_len; i++)
  252.         DEBUGMSGTL(("encode_keychange", "%02x", (int) (oldKu[i])));
  253.     DEBUGMSGTL(("encode_keychange", "n"));
  254.     rval = generate_kul(transform_type, USM_LENGTH_OID_TRANSFORM,
  255.                         engineid, engineid_len,
  256.                         oldKu, oldKu_len, oldkul, &oldkul_len);
  257.     QUITFUN(rval, main_quit);
  258.     DEBUGMSGTL(("encode_keychange", "generating old Kul (%d) (from Ku): ",
  259.                 oldkul_len));
  260.     for (i = 0; i < (int) oldkul_len; i++)
  261.         DEBUGMSGTL(("encode_keychange", "%02x", (int) (oldkul[i])));
  262.     DEBUGMSGTL(("encode_keychange", "n"));
  263.     rval = generate_kul(transform_type, USM_LENGTH_OID_TRANSFORM,
  264.                         engineid, engineid_len,
  265.                         newKu, newKu_len, newkul, &newkul_len);
  266.     QUITFUN(rval, main_quit);
  267.     DEBUGMSGTL(("encode_keychange", "generating new Kul (%d) (from Ku): ",
  268.                 oldkul_len));
  269.     for (i = 0; i < (int) newkul_len; i++)
  270.         DEBUGMSGTL(("encode_keychange", "%02x", newkul[i]));
  271.     DEBUGMSGTL(("encode_keychange", "n"));
  272.     rval = encode_keychange(transform_type, USM_LENGTH_OID_TRANSFORM,
  273.                             oldkul, oldkul_len,
  274.                             newkul, newkul_len, keychange, &keychange_len);
  275.     QUITFUN(rval, main_quit);
  276.     binary_to_hex(keychange, keychange_len, &s);
  277.     printf("%s%sn", (verbose) ? "KeyChange string:t" : "",    /* XXX stdout */
  278.            s);
  279.     /*
  280.      * Cleanup.
  281.      */
  282.   main_quit:
  283.     snmp_call_callbacks(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_SHUTDOWN,
  284.                         NULL);
  285.     SNMP_ZERO(oldpass, strlen(oldpass));
  286.     SNMP_ZERO(newpass, strlen(newpass));
  287.     SNMP_ZERO(oldKu, oldKu_len);
  288.     SNMP_ZERO(newKu, newKu_len);
  289.     SNMP_ZERO(oldkul, oldkul_len);
  290.     SNMP_ZERO(newkul, newkul_len);
  291.     SNMP_ZERO(s, strlen(s));
  292.     return rval;
  293. }                               /* end main() */
  294. /*******************************************************************-o-******
  295.  */
  296. void
  297. usage_synopsis(FILE * ofp)
  298. {
  299.     fprintf(ofp, USAGE "n
  300. n
  301.     -E [0x]<engineID> EngineID used for kul generation.n
  302.     -f Force passphrases to be read from stdin.n
  303.     -h Help.n
  304.     -N "<new_passphrase>" Passphrase used to generate new Ku.n
  305.     -O "<old_passphrase>" Passphrase used to generate old Ku.n
  306.     -P Turn off prompt indicators.n
  307.     -t md5 | sha1 HMAC hash transform type.n
  308.     -v Verbose.n
  309.     -V Visible.  Echo passphrases to terminal.n
  310. " NL, local_progname);
  311. }                               /* end usage_synopsis() */
  312. void
  313. usage_to_file(FILE * ofp)
  314. {
  315.     char           *s;
  316.     usage_synopsis(ofp);
  317.     fprintf(ofp, "n
  318.     Only -t is mandatory.  The transform is used to convert P=>Ku, convertn
  319.     Ku=>Kul, and to hash the old Kul with the random bits.n
  320. n
  321.     Passphrase will be taken from the first successful source as follows:n
  322. a) Commandline options,n
  323. b) The file "%s/%s",n
  324. c) stdin  -or-  User input from the terminal.n
  325. n
  326.     -f will require reading from the stdin/terminal, ignoring a) and b).n
  327.     -P will prevent prompts for passphrases to stdout from being printed.n
  328. n
  329.     <engineID> is intepreted as a hex string when preceeded by "0x",n
  330.     otherwise it is created to contain "text".  If nothing is given,n
  331.     <engineID> is constructed from the first IP address for the local host.n
  332. " NL, (s = getenv("HOME")) ? s : "$HOME", local_passphrase_filename);
  333.     /*
  334.      * FIX -- make this possible?
  335.      * -r [0x]<random_bits> Random bits used in KeyChange XOR.
  336.      * 
  337.      * <engineID> and <random_bits> are intepreted as hex strings when
  338.      * preceeded by "0x", otherwise <engineID> is created to contain "text"
  339.      * and <random_bits> are the same as the ascii input.
  340.      * 
  341.      * <random_bits> will be generated by SCAPI if not given.  If value is
  342.      * too long, it will be truncated; if too short, the remainder will be
  343.      * filled in with zeros.
  344.      */
  345. }                               /* end usage() */
  346. /*
  347.  * this defined for HPUX aCC because the aCC doesn't drop the 
  348.  */
  349. /*
  350.  * snmp_parse_args.c functionality if compile with -g, PKY 
  351.  */
  352. void
  353. usage(void)
  354. {
  355.     usage_to_file(stdout);
  356. }
  357. /*******************************************************************-o-******
  358.  * get_user_passphrases
  359.  *
  360.  * Returns:
  361.  * SNMPERR_SUCCESS Success.
  362.  * SNMPERR_GENERR Otherwise.
  363.  *
  364.  *
  365.  * Acquire new and old passphrases from the user:
  366.  *
  367.  * + Always prompt if 'forcepassphrase' is set.
  368.  * + Use given arguments if they are defined.
  369.  * + Otherwise read file format from PASSPHRASE_FILE.
  370.  * Sanity check existence and permissions of the path.
  371.  * ASSUME for now that PASSPHRASE_FILE is rooted only at $HOME.
  372.  * + Otherwise prompt user for passphrase(s).
  373.  * Echo input if 'visible' is set.
  374.  * Turning off 'promptindicator' makes piping in input cleaner.
  375.  *
  376.  * NOTE Only using forcepassphrase mandates taking both passphrases
  377.  * from the same source.  Otherwise processing continues until both 
  378.  * passphrases are defined.
  379.  */
  380. int
  381. get_user_passphrases(void)
  382. {
  383.     int             rval = SNMPERR_SUCCESS;
  384.     size_t          len;
  385.     char           *obuf = NULL, *nbuf = NULL;
  386.     char            path[SNMP_MAXBUF], buf[SNMP_MAXBUF], *s = NULL;
  387.     struct stat     statbuf;
  388.     FILE           *fp;
  389.     /*
  390.      * Allow prompts to the user to override all other sources.
  391.      * Nothing to do otherwise if oldpass and newpass are already defined.
  392.      */
  393.     if (forcepassphrase)
  394.         goto get_user_passphrases_prompt;
  395.     if (oldpass && newpass)
  396.         goto get_user_passphrases_quit;
  397.     /*
  398.      * Read passphrases out of PASSPHRASE_FILE.  Sanity check the
  399.      * path for existence and access first.  Refuse to read
  400.      * if the permissions are wrong.
  401.      */
  402.     s = getenv("HOME");
  403.     snprintf(path, sizeof(path), "%s/%s", s, PASSPHRASE_DIR);
  404.     path[ sizeof(path)-1 ] = 0;
  405.     /*
  406.      * Test directory. 
  407.      */
  408.     if (stat(path, &statbuf) < 0) {
  409.         fprintf(stderr, "Cannot access directory "%s".n", path);
  410.         QUITFUN(rval = SNMPERR_GENERR, get_user_passphrases_quit);
  411. #ifndef WIN32
  412.     } else if (statbuf.st_mode & (S_IRWXG | S_IRWXO)) {
  413.         fprintf(stderr,
  414.                 "Directory "%s" is accessible by group or world.n",
  415.                 path);
  416.         QUITFUN(rval = SNMPERR_GENERR, get_user_passphrases_quit);
  417. #endif                          /* !WIN32 */
  418.     }
  419.     /*
  420.      * Test file. 
  421.      */
  422.     snprintf(path, sizeof(path), "%s/%s", s, local_passphrase_filename);
  423.     path[ sizeof(path)-1 ] = 0;
  424.     if (stat(path, &statbuf) < 0) {
  425.         fprintf(stderr, "Cannot access file "%s".n", path);
  426.         QUITFUN(rval = SNMPERR_GENERR, get_user_passphrases_quit);
  427. #ifndef WIN32
  428.     } else if (statbuf.st_mode & (S_IRWXG | S_IRWXO)) {
  429.         fprintf(stderr,
  430.                 "File "%s" is accessible by group or world.n", path);
  431.         QUITFUN(rval = SNMPERR_GENERR, get_user_passphrases_quit);
  432. #endif                          /* !WIN32 */
  433.     }
  434.     /*
  435.      * Open the file. 
  436.      */
  437.     if ((fp = fopen(path, "r")) == NULL) {
  438.         fprintf(stderr, "Cannot open "%s".", path);
  439.         QUITFUN(rval = SNMPERR_GENERR, get_user_passphrases_quit);
  440.     }
  441.     /*
  442.      * Read 1st line. 
  443.      */
  444.     if (!fgets(buf, sizeof(buf), fp)) {
  445.         if (verbose) {
  446.             fprintf(stderr, "Passphrase file "%s" is empty...n", path);
  447.         }
  448.         goto get_user_passphrases_prompt;
  449.     } else if (!oldpass) {
  450.         len = strlen(buf);
  451.         if (buf[len - 1] == 'n')
  452.             buf[--len] = '';
  453.         oldpass = (char *) calloc(1, len + 1);
  454.         if (oldpass)
  455.             memcpy(oldpass, buf, len + 1);
  456.     }
  457.     /*
  458.      * Read 2nd line. 
  459.      */
  460.     if (!fgets(buf, sizeof(buf), fp)) {
  461.         if (verbose) {
  462.             fprintf(stderr, "Only one line in file "%s"...n", path);
  463.         }
  464.     } else if (!newpass) {
  465.         len = strlen(buf);
  466.         if (buf[len - 1] == 'n')
  467.             buf[--len] = '';
  468.         newpass = (char *) calloc(1, len + 1);
  469.         if (newpass)
  470.             memcpy(newpass, buf, len + 1);
  471.     }
  472.     if (oldpass && newpass)
  473.         goto get_user_passphrases_quit;
  474.     /*
  475.      * Prompt the user for passphrase entry.  Visible prompts
  476.      * may be omitted, and invisible entry may turned off.
  477.      */
  478.   get_user_passphrases_prompt:
  479.     if (forcepassphrase) {
  480.         oldpass = newpass = NULL;
  481.     }
  482.     if (!oldpass) {
  483.         oldpass = obuf
  484.             = snmp_getpassphrase((promptindicator) ? "Old passphrase: " :
  485.                                  "", visible);
  486.     }
  487.     if (!newpass) {
  488.         newpass = nbuf
  489.             = snmp_getpassphrase((promptindicator) ? "New passphrase: " :
  490.                                  "", visible);
  491.     }
  492.     /*
  493.      * Check that both passphrases were defined.
  494.      */
  495.     if (oldpass && newpass) {
  496.         goto get_user_passphrases_quit;
  497.     } else {
  498.         rval = SNMPERR_GENERR;
  499.     }
  500.   get_user_passphrases_quit:
  501.     SNMP_ZERO(buf, SNMP_MAXBUF);
  502.     if (obuf != oldpass) {
  503.         SNMP_ZERO(obuf, strlen(obuf));
  504.         SNMP_FREE(obuf);
  505.     }
  506.     if (nbuf != newpass) {
  507.         SNMP_ZERO(nbuf, strlen(nbuf));
  508.         SNMP_FREE(nbuf);
  509.     }
  510.     return rval;
  511. }                               /* end get_user_passphrases() */
  512. /*******************************************************************-o-******
  513.  * snmp_ttyecho
  514.  *
  515.  * Parameters:
  516.  * fd Descriptor of terminal on which to toggle echoing.
  517.  * echo TRUE if echoing should be on; FALSE otherwise.
  518.  *      
  519.  * Returns:
  520.  * Previous value of echo setting.
  521.  *
  522.  *
  523.  * FIX Put HAVE_TCGETATTR in autoconf?
  524.  */
  525. #ifndef HAVE_GETPASS
  526. #ifdef HAVE_TCGETATTR
  527. #include <termios.h>
  528. int
  529. snmp_ttyecho(const int fd, const int echo)
  530. {
  531.     struct termios  tio;
  532.     int             was_echo;
  533.     if (!isatty(fd))
  534.         return (-1);
  535.     tcgetattr(fd, &tio);
  536.     was_echo = (tio.c_lflag & ECHO) != 0;
  537.     if (echo)
  538.         tio.c_lflag |= (ECHO | ECHONL);
  539.     else
  540.         tio.c_lflag &= ~(ECHO | ECHONL);
  541.     tcsetattr(fd, TCSANOW, &tio);
  542.     return (was_echo);
  543. }                               /* end snmp_ttyecho() */
  544. #else
  545. #include <sgtty.h>
  546. int
  547. snmp_ttyecho(const int fd, const int echo)
  548. {
  549.     struct sgttyb   ttyparams;
  550.     int             was_echo;
  551.     if (!isatty(fd))
  552.         was_echo = -1;
  553.     else {
  554.         ioctl(fd, TIOCGETP, &ttyparams);
  555.         was_echo = (ttyparams.sg_flags & ECHO) != 0;
  556.         if (echo)
  557.             ttyparams.sg_flags = ttyparams.sg_flags | ECHO;
  558.         else
  559.             ttyparams.sg_flags = ttyparams.sg_flags & ~ECHO;
  560.         ioctl(fd, TIOCSETP, &ttyparams);
  561.     }
  562.     return (was_echo);
  563. }                               /* end snmp_ttyecho() */
  564. #endif                          /* HAVE_TCGETATTR */
  565. #endif                          /* HAVE_GETPASS */
  566. /*******************************************************************-o-******
  567.  * snmp_getpassphrase
  568.  *
  569.  * Parameters:
  570.  * *prompt (May be NULL.)
  571.  *  bvisible TRUE means echo back user input.
  572.  *      
  573.  * Returns:
  574.  * Pointer to newly allocated, null terminated string containing
  575.  * passphrase  -OR-
  576.  * NULL on error.
  577.  *
  578.  *
  579.  * Prompt stdin for a string (or passphrase).  Return a copy of the 
  580.  * input in a null terminated string.
  581.  *
  582.  * FIX Put HAVE_GETPASS in autoconf.
  583.  */
  584. char           *
  585. snmp_getpassphrase(const char *prompt, int bvisible)
  586. {
  587.     int             ti = 0;
  588.     size_t          len;
  589.     char           *bufp = NULL;
  590.     static char     buffer[SNMP_MAXBUF];
  591.     FILE           *ofp = stdout;
  592.     /*
  593.      * Query stdin for a passphrase.
  594.      */
  595. #ifdef HAVE_GETPASS
  596.     if (isatty(0)) {
  597.         return getpass((prompt) ? prompt : "");
  598.     }
  599. #endif
  600.     fputs((prompt) ? prompt : "", ofp);
  601.     if (!bvisible) {
  602.         ti = snmp_ttyecho(0, 0);
  603.     }
  604.     fgets(buffer, sizeof(buffer), stdin);
  605.     if (!bvisible) {
  606.         ti = snmp_ttyecho(0, ti);
  607.         fputs("n", ofp);
  608.     }
  609.     /*
  610.      * Copy the input and zero out the read-in buffer.
  611.      */
  612.     len = strlen(buffer);
  613.     if (buffer[len - 1] == 'n')
  614.         buffer[--len] = '';
  615.     bufp = (char *) calloc(1, len + 1);
  616.     if (bufp)
  617.         memcpy(bufp, buffer, len + 1);
  618.     SNMP_ZERO(buffer, SNMP_MAXBUF);
  619.     return bufp;
  620. }                               /* end snmp_getpassphrase() */
  621. #ifdef WIN32
  622. int
  623. snmp_ttyecho(const int fd, const int echo)
  624. {
  625.     return 0;
  626. }
  627. /*
  628.  * stops at the first newline, carrier return, or backspace.
  629.  * WARNING! _getch does NOT read <Ctrl-C>
  630.  */
  631. char           *
  632. getpass(const char *prompt)
  633. {
  634.     static char     pbuf[128];
  635.     int             ch, lim;
  636.     _cputs(prompt);
  637.     for (ch = 0, lim = 0; ch != 'n' && lim < sizeof(pbuf)-1;) {
  638.         ch = _getch();          /* look ma, no echo ! */
  639.         if (ch == 'r' || ch == 'n' || ch == 'b')
  640.             break;
  641.         pbuf[lim++] = ch;
  642.     }
  643.     pbuf[lim] = '';
  644.     puts("n");
  645.     return pbuf;
  646. }
  647. #endif                          /* WIN32 */