> > 2.  For Linux systems, avoid using the glibc version of ruserpass(), and use
> > the version supplied with nmh.  There's an additional problem here -
> > ruserpass() calls getpass(), and in glibc, the getpass() flushes standard input
> > before prompting the user for a password.  When a program like exmh uses 'inc',
> > it feeds in the password as standard input with code like:
> > 
> >     exec inc +inbox -truncate -nochangecur -width 100 << password

i looked at the most recent glibc sources, and did not find any signs of
stdin flushing. however as a precautionary measure, i agree that it would
be good to have our own  getpass().

i've taken glibc getpass, stripped out some flock-ing code that didn't
compile on BSD, and made it into a patch (attached). it should depend only
on termios.h (add to the includes) and stdio and strings.h, which are
included in nmh.h. so hopefully, this should be pretty portable.

i've tested it on redhat linux 6.1 and netbsd 1.4.2. please let me know if
this successfully compiles on other platforms, since i don't want to
commit it without being sure it'll work.

this works with such scripts as:
perl -e 'open(STDIN, "</dev/null"); print `echo "password" | 
uip/msgchk -host pophost`;'

please tell me if exmh likes this, as well as other frontends to nmh.

shantonu

*-------------------------------------------*
|Shantonu Sen * (617)225-6778 * [EMAIL PROTECTED]|
|Electrical Engineering and Computer Science|
|Massachusetts Institute of Technology, 2002|
*-------------------------------------------*

*** nmh-other/nmh/sbr/ruserpass.c       Fri Apr 30 14:08:34 1999
--- nmh/sbr/ruserpass.c Tue May  2 02:05:42 2000
***************
*** 20,25 ****
--- 20,26 ----
  #include <h/mh.h>
  #include <pwd.h>
  #include <errno.h>
+ #include <termios.h>
  
  static FILE *cfile;
  
***************
*** 58,63 ****
--- 59,65 ----
   */
  static int token(void);
  
+ char *getpass (const char *prompt);
  
  int
  ruserpass(char *host, char **aname, char **apass)
***************
*** 215,218 ****
--- 217,296 ----
        if (!strcmp(t->tokstr, tokval))
            return (t->tval);
      return (ID);
+ }
+ 
+ /* The following getpass routine is lifted from glibc 2.1.3, minues
+    a lot of non-portable flocking.
+    Contact Shantonu Sen <[EMAIL PROTECTED]> if this does not
+    compile on your platform */
+ 
+ /* It is desirable to use this bit on systems that have it.
+    The only bit of terminal state we want to twiddle is echoing, which is
+    done in software; there is no need to change the state of the terminal
+    hardware.  */
+ 
+ #ifndef TCSASOFT
+ #define TCSASOFT 0
+ #endif
+ 
+ char *
+ getpass (const char *prompt)
+ {
+   FILE *in, *out;
+   struct termios s, t;
+   int tty_changed;
+   static char buf[128];
+   ssize_t nread;
+ 
+   /* Try to write to and read from the terminal if we can.
+      If we can't open the terminal, use stderr and stdin.  */
+ 
+   in = fopen ("/dev/tty", "w+");
+   if (in == NULL)
+     {
+       in = stdin;
+       out = stderr;
+     }
+   else
+     out = in;
+ 
+   if (tcgetattr (fileno (in), &t) == 0)
+     {
+       /* Save the old one. */
+       s = t;
+       /* Tricky, tricky. */
+       t.c_lflag &= ~(ECHO|ISIG);
+       tty_changed = (tcsetattr (fileno (in), TCSAFLUSH|TCSASOFT, &t) == 0);
+     }
+   else
+     tty_changed = 0;
+ 
+   fputs(prompt, out);
+ 
+   /* Read the password.  */
+   fgets(buf, sizeof(buf) - 1, stdin);
+   nread = strlen(buf);
+   if (buf != NULL)
+     {
+       if (nread < 0)
+         buf[0] = '\0';
+       else if (buf[nread - 1] == '\n')
+         {
+           /* Remove the newline.  */
+           buf[nread - 1] = '\0';
+           if (tty_changed)
+             /* Write the newline that was not echoed.  */
+             fputc('\n', out);
+         }
+     }
+ 
+   /* Restore the original setting.  */
+   if (tty_changed)
+     (void) tcsetattr (fileno (in), TCSAFLUSH|TCSASOFT, &s);
+ 
+   if (in != stdin)
+     /* We opened the terminal; now close it.  */
+     fclose (in);
+ 
+   return buf;
  }

Reply via email to