Hi,

sorry if it took this long to get to this patch.

Unfortunately this patch should be rebased on master, because right now
it does not apply and I cannot test.
Can you please rebase and resubmit it (with v2 in the subject)?

However, I have some comments below.

On 13/01/2021 20:19, Tõivo Leedjärv wrote:
> The getpass() function is present in SUSv2, but marked LEGACY. It is
> removed in POSIX.1-2001. Additionally, on Solaris getpass() returns
> maximum 8 bytes. This will make longer passwords fail with no
> possibility for user to know what is happening.
> 

Indeed the manpage clearly says that this function is obsolete, and
users should look into termios.

I believe termios.h should normally be available on any *nix system,
therefore it should be ok to switch to it.

> This patch removes usage of getpass() completely and replaces it with
> direct implementation of what getpass() does: opens tty (existing code),
> outputs the prompt (existing code), turns off echoing (new code), reads
> one line (existing code shared with echoed mode), restores tty state
> (new code) and closes tty (existing code).
> 
> Signed-off-by: Tõivo Leedjärv <69477666+tleedj...@users.noreply.github.com>
> ---
>  configure.ac                  |  4 ++-
>  src/openvpn/console_builtin.c | 63 +++++++++++++++++++++--------------
>  2 files changed, 41 insertions(+), 26 deletions(-)
> 
> diff --git a/configure.ac b/configure.ac
> index 1ab8fe59..2c094da7 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -645,7 +645,7 @@ AC_FUNC_FORK
> 
>  AC_CHECK_FUNCS([ \
>         daemon chroot getpwnam setuid nice system getpid dup dup2 \
> -       getpass syslog openlog mlockall getgrnam setgid \
> +       syslog openlog mlockall getgrnam setgid \
>         setgroups stat flock readv writev time gettimeofday \
>         ctime memset vsnprintf strdup \
>         setsid chdir putenv getpeername unlink \
> @@ -653,6 +653,8 @@ AC_CHECK_FUNCS([ \
>         epoll_create strsep \
>  ])
> 
> +AC_CHECK_HEADERS([termios.h])

We already have a big list of headers that we check. May it make sense
to append termios.h there?

> +
>  AC_CHECK_LIB(
>         [dl],
>         [dlopen],
> diff --git a/src/openvpn/console_builtin.c b/src/openvpn/console_builtin.c
> index 445928bf..f1d91b32 100644
> --- a/src/openvpn/console_builtin.c
> +++ b/src/openvpn/console_builtin.c
> @@ -40,6 +40,10 @@
>  #include "buffer.h"
>  #include "misc.h"
> 
> +#ifdef HAVE_TERMIOS_H
> +#include <termios.h>
> +#endif
> +
>  #ifdef _WIN32
> 
>  #include "win32.h"
> @@ -138,7 +142,7 @@ get_console_input_win32(const char *prompt, const
> bool echo, char *input, const
>  #endif   /* _WIN32 */
> 
> 
> -#ifdef HAVE_GETPASS
> +#ifdef HAVE_TERMIOS_H
> 
>  /**
>   * Open the current console TTY for read/write operations
> @@ -177,7 +181,7 @@ close_tty(FILE *fp)
>      }
>  }
> 
> -#endif   /* HAVE_GETPASS */
> +#endif   /* HAVE_TERMIOS_H */
> 
> 
>  /**
> @@ -201,7 +205,9 @@ get_console_input(const char *prompt, const bool
> echo, char *input, const int ca
> 
>  #if defined(_WIN32)
>      return get_console_input_win32(prompt, echo, input, capacity);
> -#elif defined(HAVE_GETPASS)
> +#elif defined(HAVE_TERMIOS_H)
> +    int restore_tty = 0;

shouldn't this be bool?

> +    struct termios tty_a, tty_save;

how about tty_tmp instead of tty_a ?

> 
>      /* did we --daemon'ize before asking for passwords?
>       * (in which case neither stdin or stderr are connected to a tty and
> @@ -220,33 +226,40 @@ get_console_input(const char *prompt, const bool
> echo, char *input, const int ca
>          close(fd);
>      }
> 
> -    if (echo)
> -    {
> -        FILE *fp;
> +    FILE *fp;
> 
> -        fp = open_tty(true);
> -        fprintf(fp, "%s", prompt);
> -        fflush(fp);
> -        close_tty(fp);
> +    fp = open_tty(true);

since you are touching this code, please move the initialization inline
with the declaration.

> +    fprintf(fp, "%s", prompt);
> +    fflush(fp);
> +    close_tty(fp);
> 
> -        fp = open_tty(false);
> -        if (fgets(input, capacity, fp) != NULL)
> -        {
> -            chomp(input);
> -            ret = true;
> -        }
> -        close_tty(fp);
> +    fp = open_tty(false);
> +
> +    if (!echo && (tcgetattr(fileno(fp), &tty_a) == 0))
> +    {
> +        tty_save = tty_a;
> +        tty_a.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL | ISIG);
> +        restore_tty = (tcsetattr(fileno(fp), TCSAFLUSH, &tty_a) == 0);
>      }
> -    else
> +
> +    if (fgets(input, capacity, fp) != NULL)
>      {
> -        char *gp = getpass(prompt);
> -        if (gp)
> -        {
> -            strncpynt(input, gp, capacity);
> -            secure_memzero(gp, strlen(gp));
> -            ret = true;
> -        }
> +        chomp(input);
> +        ret = true;
>      }
> +
> +    if (!echo && restore_tty)

I guess we can simply check restore_tty being true?

> +    {
> +        (void) tcsetattr(fileno(fp), TCSAFLUSH, &tty_save);

We should not need to cast to void - I don't think we have warnings set
for non-checked return values.

> +
> +        /* Echo the non-echoed newline */
> +        close_tty(fp);
> +        fp = open_tty(true);
> +        fprintf(fp, "\n");
> +        fflush(fp);
> +    }
> +
> +    close_tty(fp);
>  #else  /* if defined(_WIN32) */
>      msg(M_FATAL, "Sorry, but I can't get console input on this OS
> (%s)", prompt);
>  #endif /* if defined(_WIN32) */
> 

The rest looks good to me and I believe it is a valid patch.

Once we have a patch that can be committed on master I will perform some
tests.

Best Regards,


-- 
Antonio Quartulli


_______________________________________________
Openvpn-devel mailing list
Openvpn-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/openvpn-devel

Reply via email to