summaryrefslogtreecommitdiff
path: root/src/common/sprompt.c
diff options
context:
space:
mode:
authorTom Lane2020-09-04 00:09:18 +0000
committerTom Lane2020-09-04 00:09:18 +0000
commit67a472d71c98c3d2fa322a1b4013080b20720b98 (patch)
tree4b7a6254ec7d2da7f8b36b8eaf645c30a452c92c /src/common/sprompt.c
parentbe4b0c0077e6a1f7be0965f8d93696e0e0eadb52 (diff)
Remove arbitrary restrictions on password length.
This patch started out with the goal of harmonizing various arbitrary limits on password length, but after awhile a better idea emerged: let's just get rid of those fixed limits. recv_password_packet() has an arbitrary limit on the packet size, which we don't really need, so just drop it. (Note that this doesn't really affect anything for MD5 or SCRAM password verification, since those will hash the user's password to something shorter anyway. It does matter for auth methods that require a cleartext password.) Likewise remove the arbitrary error condition in pg_saslprep(). The remaining limits are mostly in client-side code that prompts for passwords. To improve those, refactor simple_prompt() so that it allocates its own result buffer that can be made as big as necessary. Actually, it proves best to make a separate routine pg_get_line() that has essentially the semantics of fgets(), except that it allocates a suitable result buffer and hence will never return a truncated line. (pg_get_line has a lot of potential applications to replace randomly-sized fgets buffers elsewhere, but I'll leave that for another patch.) I built pg_get_line() atop stringinfo.c, which requires moving that code to src/common/; but that seems fine since it was a poor fit for src/port/ anyway. This patch is mostly mine, but it owes a good deal to Nathan Bossart who pressed for a solution to the password length problem and created a predecessor patch. Also thanks to Peter Eisentraut and Stephen Frost for ideas and discussion. Discussion: https://postgr.es/m/09512C4F-8CB9-4021-B455-EF4C4F0D55A0@amazon.com
Diffstat (limited to 'src/common/sprompt.c')
-rw-r--r--src/common/sprompt.c159
1 files changed, 159 insertions, 0 deletions
diff --git a/src/common/sprompt.c b/src/common/sprompt.c
new file mode 100644
index 0000000000..0ec75da5bf
--- /dev/null
+++ b/src/common/sprompt.c
@@ -0,0 +1,159 @@
+/*-------------------------------------------------------------------------
+ *
+ * sprompt.c
+ * simple_prompt() routine
+ *
+ * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * src/common/sprompt.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "c.h"
+
+#include "common/fe_memutils.h"
+#include "common/string.h"
+
+#ifdef HAVE_TERMIOS_H
+#include <termios.h>
+#endif
+
+
+/*
+ * simple_prompt
+ *
+ * Generalized function especially intended for reading in usernames and
+ * passwords interactively. Reads from /dev/tty or stdin/stderr.
+ *
+ * prompt: The prompt to print, or NULL if none (automatically localized)
+ * echo: Set to false if you want to hide what is entered (for passwords)
+ *
+ * The input (without trailing newline) is returned as a malloc'd string.
+ * Caller is responsible for freeing it when done.
+ */
+char *
+simple_prompt(const char *prompt, bool echo)
+{
+ char *result;
+ FILE *termin,
+ *termout;
+#if defined(HAVE_TERMIOS_H)
+ struct termios t_orig,
+ t;
+#elif defined(WIN32)
+ HANDLE t = NULL;
+ DWORD t_orig = 0;
+#endif
+
+#ifdef WIN32
+
+ /*
+ * A Windows console has an "input code page" and an "output code page";
+ * these usually match each other, but they rarely match the "Windows ANSI
+ * code page" defined at system boot and expected of "char *" arguments to
+ * Windows API functions. The Microsoft CRT write() implementation
+ * automatically converts text between these code pages when writing to a
+ * console. To identify such file descriptors, it calls GetConsoleMode()
+ * on the underlying HANDLE, which in turn requires GENERIC_READ access on
+ * the HANDLE. Opening termout in mode "w+" allows that detection to
+ * succeed. Otherwise, write() would not recognize the descriptor as a
+ * console, and non-ASCII characters would display incorrectly.
+ *
+ * XXX fgets() still receives text in the console's input code page. This
+ * makes non-ASCII credentials unportable.
+ *
+ * Unintuitively, we also open termin in mode "w+", even though we only
+ * read it; that's needed for SetConsoleMode() to succeed.
+ */
+ termin = fopen("CONIN$", "w+");
+ termout = fopen("CONOUT$", "w+");
+#else
+
+ /*
+ * Do not try to collapse these into one "w+" mode file. Doesn't work on
+ * some platforms (eg, HPUX 10.20).
+ */
+ termin = fopen("/dev/tty", "r");
+ termout = fopen("/dev/tty", "w");
+#endif
+ if (!termin || !termout
+#ifdef WIN32
+
+ /*
+ * Direct console I/O does not work from the MSYS 1.0.10 console. Writes
+ * reach nowhere user-visible; reads block indefinitely. XXX This affects
+ * most Windows terminal environments, including rxvt, mintty, Cygwin
+ * xterm, Cygwin sshd, and PowerShell ISE. Switch to a more-generic test.
+ */
+ || (getenv("OSTYPE") && strcmp(getenv("OSTYPE"), "msys") == 0)
+#endif
+ )
+ {
+ if (termin)
+ fclose(termin);
+ if (termout)
+ fclose(termout);
+ termin = stdin;
+ termout = stderr;
+ }
+
+ if (!echo)
+ {
+#if defined(HAVE_TERMIOS_H)
+ /* disable echo via tcgetattr/tcsetattr */
+ tcgetattr(fileno(termin), &t);
+ t_orig = t;
+ t.c_lflag &= ~ECHO;
+ tcsetattr(fileno(termin), TCSAFLUSH, &t);
+#elif defined(WIN32)
+ /* need the file's HANDLE to turn echo off */
+ t = (HANDLE) _get_osfhandle(_fileno(termin));
+
+ /* save the old configuration first */
+ GetConsoleMode(t, &t_orig);
+
+ /* set to the new mode */
+ SetConsoleMode(t, ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT);
+#endif
+ }
+
+ if (prompt)
+ {
+ fputs(_(prompt), termout);
+ fflush(termout);
+ }
+
+ result = pg_get_line(termin);
+
+ /* If we failed to read anything, just return an empty string */
+ if (result == NULL)
+ result = pg_strdup("");
+
+ /* strip trailing newline, including \r in case we're on Windows */
+ (void) pg_strip_crlf(result);
+
+ if (!echo)
+ {
+ /* restore previous echo behavior, then echo \n */
+#if defined(HAVE_TERMIOS_H)
+ tcsetattr(fileno(termin), TCSAFLUSH, &t_orig);
+ fputs("\n", termout);
+ fflush(termout);
+#elif defined(WIN32)
+ SetConsoleMode(t, t_orig);
+ fputs("\n", termout);
+ fflush(termout);
+#endif
+ }
+
+ if (termin != stdin)
+ {
+ fclose(termin);
+ fclose(termout);
+ }
+
+ return result;
+}