Re: Maximum password length - Mailing list pgsql-hackers

From Tom Lane
Subject Re: Maximum password length
Date
Msg-id 635718.1599153497@sss.pgh.pa.us
Whole thread Raw
In response to Re: Maximum password length  (Tom Lane <tgl@sss.pgh.pa.us>)
Responses Re: Maximum password length
List pgsql-hackers
I wrote:
> This could be refined; in particular, I think that most of the
> password-prompting sites could drop their separate have_password
> flags in favor of checking whether the password pointer is NULL
> or not.  That would likely also prove that some of the free(password)
> calls I sprinkled in are unnecessary.

Hearing no objections to this general plan, I went ahead and did that
cleanup.  This version seems committable to me.

            regards, tom lane

diff --git a/contrib/oid2name/oid2name.c b/contrib/oid2name/oid2name.c
index 91b7958c48..5a884e2904 100644
--- a/contrib/oid2name/oid2name.c
+++ b/contrib/oid2name/oid2name.c
@@ -12,6 +12,7 @@
 #include "catalog/pg_class_d.h"
 #include "common/connect.h"
 #include "common/logging.h"
+#include "common/string.h"
 #include "getopt_long.h"
 #include "libpq-fe.h"
 #include "pg_getopt.h"
@@ -293,8 +294,7 @@ PGconn *
 sql_conn(struct options *my_opts)
 {
     PGconn       *conn;
-    bool        have_password = false;
-    char        password[100];
+    char       *password = NULL;
     bool        new_pass;
     PGresult   *res;

@@ -316,7 +316,7 @@ sql_conn(struct options *my_opts)
         keywords[2] = "user";
         values[2] = my_opts->username;
         keywords[3] = "password";
-        values[3] = have_password ? password : NULL;
+        values[3] = password;
         keywords[4] = "dbname";
         values[4] = my_opts->dbname;
         keywords[5] = "fallback_application_name";
@@ -336,11 +336,10 @@ sql_conn(struct options *my_opts)

         if (PQstatus(conn) == CONNECTION_BAD &&
             PQconnectionNeedsPassword(conn) &&
-            !have_password)
+            !password)
         {
             PQfinish(conn);
-            simple_prompt("Password: ", password, sizeof(password), false);
-            have_password = true;
+            password = simple_prompt("Password: ", false);
             new_pass = true;
         }
     } while (new_pass);
diff --git a/contrib/vacuumlo/vacuumlo.c b/contrib/vacuumlo/vacuumlo.c
index e4019fafaa..532cc596c4 100644
--- a/contrib/vacuumlo/vacuumlo.c
+++ b/contrib/vacuumlo/vacuumlo.c
@@ -24,6 +24,7 @@
 #include "catalog/pg_class_d.h"
 #include "common/connect.h"
 #include "common/logging.h"
+#include "common/string.h"
 #include "getopt_long.h"
 #include "libpq-fe.h"
 #include "pg_getopt.h"
@@ -69,15 +70,11 @@ vacuumlo(const char *database, const struct _param *param)
     int            i;
     bool        new_pass;
     bool        success = true;
-    static bool have_password = false;
-    static char password[100];
+    static char *password = NULL;

     /* Note: password can be carried over from a previous call */
-    if (param->pg_prompt == TRI_YES && !have_password)
-    {
-        simple_prompt("Password: ", password, sizeof(password), false);
-        have_password = true;
-    }
+    if (param->pg_prompt == TRI_YES && !password)
+        password = simple_prompt("Password: ", false);

     /*
      * Start the connection.  Loop until we have a password if requested by
@@ -97,7 +94,7 @@ vacuumlo(const char *database, const struct _param *param)
         keywords[2] = "user";
         values[2] = param->pg_user;
         keywords[3] = "password";
-        values[3] = have_password ? password : NULL;
+        values[3] = password;
         keywords[4] = "dbname";
         values[4] = database;
         keywords[5] = "fallback_application_name";
@@ -115,12 +112,11 @@ vacuumlo(const char *database, const struct _param *param)

         if (PQstatus(conn) == CONNECTION_BAD &&
             PQconnectionNeedsPassword(conn) &&
-            !have_password &&
+            !password &&
             param->pg_prompt != TRI_NO)
         {
             PQfinish(conn);
-            simple_prompt("Password: ", password, sizeof(password), false);
-            have_password = true;
+            password = simple_prompt("Password: ", false);
             new_pass = true;
         }
     } while (new_pass);
diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c
index 02b6c3f127..36565df4fc 100644
--- a/src/backend/libpq/auth.c
+++ b/src/backend/libpq/auth.c
@@ -698,7 +698,7 @@ recv_password_packet(Port *port)
     }

     initStringInfo(&buf);
-    if (pq_getmessage(&buf, 1000))    /* receive password */
+    if (pq_getmessage(&buf, 0)) /* receive password */
     {
         /* EOF - pq_getmessage already logged a suitable message */
         pfree(buf.data);
diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c
index 786672b1b6..b62f8f6a5e 100644
--- a/src/bin/initdb/initdb.c
+++ b/src/bin/initdb/initdb.c
@@ -67,6 +67,7 @@
 #include "common/file_utils.h"
 #include "common/logging.h"
 #include "common/restricted_token.h"
+#include "common/string.h"
 #include "common/username.h"
 #include "fe_utils/string_utils.h"
 #include "getaddrinfo.h"
@@ -1481,23 +1482,25 @@ setup_auth(FILE *cmdfd)
 static void
 get_su_pwd(void)
 {
-    char        pwd1[100];
-    char        pwd2[100];
+    char       *pwd1;

     if (pwprompt)
     {
         /*
          * Read password from terminal
          */
+        char       *pwd2;
+
         printf("\n");
         fflush(stdout);
-        simple_prompt("Enter new superuser password: ", pwd1, sizeof(pwd1), false);
-        simple_prompt("Enter it again: ", pwd2, sizeof(pwd2), false);
+        pwd1 = simple_prompt("Enter new superuser password: ", false);
+        pwd2 = simple_prompt("Enter it again: ", false);
         if (strcmp(pwd1, pwd2) != 0)
         {
             fprintf(stderr, _("Passwords didn't match.\n"));
             exit(1);
         }
+        free(pwd2);
     }
     else
     {
@@ -1510,7 +1513,7 @@ get_su_pwd(void)
          * for now.
          */
         FILE       *pwf = fopen(pwfilename, "r");
-        int            i;
+        char        pwdbuf[8192];

         if (!pwf)
         {
@@ -1518,7 +1521,7 @@ get_su_pwd(void)
                          pwfilename);
             exit(1);
         }
-        if (!fgets(pwd1, sizeof(pwd1), pwf))
+        if (!fgets(pwdbuf, sizeof(pwdbuf), pwf))
         {
             if (ferror(pwf))
                 pg_log_error("could not read password from file \"%s\": %m",
@@ -1530,12 +1533,11 @@ get_su_pwd(void)
         }
         fclose(pwf);

-        i = strlen(pwd1);
-        while (i > 0 && (pwd1[i - 1] == '\r' || pwd1[i - 1] == '\n'))
-            pwd1[--i] = '\0';
+        (void) pg_strip_crlf(pwdbuf);
+        pwd1 = pg_strdup(pwdbuf);
     }

-    superuser_password = pg_strdup(pwd1);
+    superuser_password = pwd1;
 }

 /*
diff --git a/src/bin/pg_basebackup/streamutil.c b/src/bin/pg_basebackup/streamutil.c
index c08003e7f2..be653ebb2d 100644
--- a/src/bin/pg_basebackup/streamutil.c
+++ b/src/bin/pg_basebackup/streamutil.c
@@ -22,6 +22,7 @@
 #include "common/fe_memutils.h"
 #include "common/file_perm.h"
 #include "common/logging.h"
+#include "common/string.h"
 #include "datatype/timestamp.h"
 #include "port/pg_bswap.h"
 #include "pqexpbuffer.h"
@@ -49,8 +50,7 @@ char       *dbuser = NULL;
 char       *dbport = NULL;
 char       *dbname = NULL;
 int            dbgetpassword = 0;    /* 0=auto, -1=never, 1=always */
-static bool have_password = false;
-static char password[100];
+static char *password = NULL;
 PGconn       *conn = NULL;

 /*
@@ -150,20 +150,21 @@ GetConnection(void)
     }

     /* If -W was given, force prompt for password, but only the first time */
-    need_password = (dbgetpassword == 1 && !have_password);
+    need_password = (dbgetpassword == 1 && !password);

     do
     {
         /* Get a new password if appropriate */
         if (need_password)
         {
-            simple_prompt("Password: ", password, sizeof(password), false);
-            have_password = true;
+            if (password)
+                free(password);
+            password = simple_prompt("Password: ", false);
             need_password = false;
         }

         /* Use (or reuse, on a subsequent connection) password if we have it */
-        if (have_password)
+        if (password)
         {
             keywords[i] = "password";
             values[i] = password;
diff --git a/src/bin/pg_dump/pg_backup_db.c b/src/bin/pg_dump/pg_backup_db.c
index 94af11b80a..12899e26e2 100644
--- a/src/bin/pg_dump/pg_backup_db.c
+++ b/src/bin/pg_dump/pg_backup_db.c
@@ -18,6 +18,7 @@
 #endif

 #include "common/connect.h"
+#include "common/string.h"
 #include "dumputils.h"
 #include "fe_utils/string_utils.h"
 #include "parallel.h"
@@ -122,7 +123,6 @@ _connectDB(ArchiveHandle *AH, const char *reqdb, const char *requser)
     const char *newdb;
     const char *newuser;
     char       *password;
-    char        passbuf[100];
     bool        new_pass;

     if (!reqdb)
@@ -141,10 +141,7 @@ _connectDB(ArchiveHandle *AH, const char *reqdb, const char *requser)
     password = AH->savedPassword;

     if (AH->promptPassword == TRI_YES && password == NULL)
-    {
-        simple_prompt("Password: ", passbuf, sizeof(passbuf), false);
-        password = passbuf;
-    }
+        password = simple_prompt("Password: ", false);

     initPQExpBuffer(&connstr);
     appendPQExpBufferStr(&connstr, "dbname=");
@@ -191,8 +188,9 @@ _connectDB(ArchiveHandle *AH, const char *reqdb, const char *requser)

             if (AH->promptPassword != TRI_NO)
             {
-                simple_prompt("Password: ", passbuf, sizeof(passbuf), false);
-                password = passbuf;
+                if (password && password != AH->savedPassword)
+                    free(password);
+                password = simple_prompt("Password: ", false);
             }
             else
                 fatal("connection needs password");
@@ -201,6 +199,9 @@ _connectDB(ArchiveHandle *AH, const char *reqdb, const char *requser)
         }
     } while (new_pass);

+    if (password && password != AH->savedPassword)
+        free(password);
+
     /*
      * We want to remember connection's actual password, whether or not we got
      * it by prompting.  So we don't just store the password variable.
@@ -242,7 +243,6 @@ ConnectDatabase(Archive *AHX,
 {
     ArchiveHandle *AH = (ArchiveHandle *) AHX;
     char       *password;
-    char        passbuf[100];
     bool        new_pass;

     if (AH->connection)
@@ -251,10 +251,8 @@ ConnectDatabase(Archive *AHX,
     password = AH->savedPassword;

     if (prompt_password == TRI_YES && password == NULL)
-    {
-        simple_prompt("Password: ", passbuf, sizeof(passbuf), false);
-        password = passbuf;
-    }
+        password = simple_prompt("Password: ", false);
+
     AH->promptPassword = prompt_password;

     /*
@@ -293,8 +291,7 @@ ConnectDatabase(Archive *AHX,
             prompt_password != TRI_NO)
         {
             PQfinish(AH->connection);
-            simple_prompt("Password: ", passbuf, sizeof(passbuf), false);
-            password = passbuf;
+            password = simple_prompt("Password: ", false);
             new_pass = true;
         }
     } while (new_pass);
@@ -309,6 +306,9 @@ ConnectDatabase(Archive *AHX,
     PQclear(ExecuteSqlQueryForSingleRow((Archive *) AH,
                                         ALWAYS_SECURE_SEARCH_PATH_SQL));

+    if (password && password != AH->savedPassword)
+        free(password);
+
     /*
      * We want to remember connection's actual password, whether or not we got
      * it by prompting.  So we don't just store the password variable.
diff --git a/src/bin/pg_dump/pg_dumpall.c b/src/bin/pg_dump/pg_dumpall.c
index 2c82b39af0..97d2b8dac1 100644
--- a/src/bin/pg_dump/pg_dumpall.c
+++ b/src/bin/pg_dump/pg_dumpall.c
@@ -21,6 +21,7 @@
 #include "common/connect.h"
 #include "common/file_utils.h"
 #include "common/logging.h"
+#include "common/string.h"
 #include "dumputils.h"
 #include "fe_utils/string_utils.h"
 #include "getopt_long.h"
@@ -1643,14 +1644,10 @@ connectDatabase(const char *dbname, const char *connection_string,
     const char **keywords = NULL;
     const char **values = NULL;
     PQconninfoOption *conn_opts = NULL;
-    static bool have_password = false;
-    static char password[100];
+    static char *password = NULL;

-    if (prompt_password == TRI_YES && !have_password)
-    {
-        simple_prompt("Password: ", password, sizeof(password), false);
-        have_password = true;
-    }
+    if (prompt_password == TRI_YES && !password)
+        password = simple_prompt("Password: ", false);

     /*
      * Start the connection.  Loop until we have a password if requested by
@@ -1730,7 +1727,7 @@ connectDatabase(const char *dbname, const char *connection_string,
             values[i] = pguser;
             i++;
         }
-        if (have_password)
+        if (password)
         {
             keywords[i] = "password";
             values[i] = password;
@@ -1757,12 +1754,11 @@ connectDatabase(const char *dbname, const char *connection_string,

         if (PQstatus(conn) == CONNECTION_BAD &&
             PQconnectionNeedsPassword(conn) &&
-            !have_password &&
+            !password &&
             prompt_password != TRI_NO)
         {
             PQfinish(conn);
-            simple_prompt("Password: ", password, sizeof(password), false);
-            have_password = true;
+            password = simple_prompt("Password: ", false);
             new_pass = true;
         }
     } while (new_pass);
diff --git a/src/bin/pgbench/pgbench.c b/src/bin/pgbench/pgbench.c
index 08a5947a9e..332eabf637 100644
--- a/src/bin/pgbench/pgbench.c
+++ b/src/bin/pgbench/pgbench.c
@@ -59,6 +59,7 @@

 #include "common/int.h"
 #include "common/logging.h"
+#include "common/string.h"
 #include "fe_utils/cancel.h"
 #include "fe_utils/conditional.h"
 #include "getopt_long.h"
@@ -1174,8 +1175,7 @@ doConnect(void)
 {
     PGconn       *conn;
     bool        new_pass;
-    static bool have_password = false;
-    static char password[100];
+    static char *password = NULL;

     /*
      * Start the connection.  Loop until we have a password if requested by
@@ -1195,7 +1195,7 @@ doConnect(void)
         keywords[2] = "user";
         values[2] = login;
         keywords[3] = "password";
-        values[3] = have_password ? password : NULL;
+        values[3] = password;
         keywords[4] = "dbname";
         values[4] = dbName;
         keywords[5] = "fallback_application_name";
@@ -1215,11 +1215,10 @@ doConnect(void)

         if (PQstatus(conn) == CONNECTION_BAD &&
             PQconnectionNeedsPassword(conn) &&
-            !have_password)
+            !password)
         {
             PQfinish(conn);
-            simple_prompt("Password: ", password, sizeof(password), false);
-            have_password = true;
+            password = simple_prompt("Password: ", false);
             new_pass = true;
         }
     } while (new_pass);
diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
index 9902a4a2ba..d4aa0976b5 100644
--- a/src/bin/psql/command.c
+++ b/src/bin/psql/command.c
@@ -26,6 +26,7 @@
 #include "command.h"
 #include "common.h"
 #include "common/logging.h"
+#include "common/string.h"
 #include "copy.h"
 #include "crosstabview.h"
 #include "describe.h"
@@ -1964,11 +1965,11 @@ exec_command_password(PsqlScanState scan_state, bool active_branch)
     {
         char       *opt0 = psql_scan_slash_option(scan_state,
                                                   OT_SQLID, NULL, true);
-        char        pw1[100];
-        char        pw2[100];
+        char       *pw1;
+        char       *pw2;

-        simple_prompt("Enter new password: ", pw1, sizeof(pw1), false);
-        simple_prompt("Enter it again: ", pw2, sizeof(pw2), false);
+        pw1 = simple_prompt("Enter new password: ", false);
+        pw2 = simple_prompt("Enter it again: ", false);

         if (strcmp(pw1, pw2) != 0)
         {
@@ -2013,6 +2014,8 @@ exec_command_password(PsqlScanState scan_state, bool active_branch)

         if (opt0)
             free(opt0);
+        free(pw1);
+        free(pw2);
     }
     else
         ignore_slash_options(scan_state);
@@ -2058,8 +2061,7 @@ exec_command_prompt(PsqlScanState scan_state, bool active_branch,

             if (!pset.inputfile)
             {
-                result = (char *) pg_malloc(4096);
-                simple_prompt(prompt_text, result, 4096, true);
+                result = simple_prompt(prompt_text, true);
             }
             else
             {
@@ -2982,19 +2984,19 @@ copy_previous_query(PQExpBuffer query_buf, PQExpBuffer previous_buf)
 static char *
 prompt_for_password(const char *username)
 {
-    char        buf[100];
+    char       *result;

     if (username == NULL || username[0] == '\0')
-        simple_prompt("Password: ", buf, sizeof(buf), false);
+        result = simple_prompt("Password: ", false);
     else
     {
         char       *prompt_text;

         prompt_text = psprintf(_("Password for user %s: "), username);
-        simple_prompt(prompt_text, buf, sizeof(buf), false);
+        result = simple_prompt(prompt_text, false);
         free(prompt_text);
     }
-    return pg_strdup(buf);
+    return result;
 }

 static bool
diff --git a/src/bin/psql/startup.c b/src/bin/psql/startup.c
index 3302bd4dd3..8232a0143b 100644
--- a/src/bin/psql/startup.c
+++ b/src/bin/psql/startup.c
@@ -17,6 +17,7 @@
 #include "command.h"
 #include "common.h"
 #include "common/logging.h"
+#include "common/string.h"
 #include "describe.h"
 #include "fe_utils/print.h"
 #include "getopt_long.h"
@@ -119,8 +120,7 @@ main(int argc, char *argv[])
 {
     struct adhoc_opts options;
     int            successResult;
-    bool        have_password = false;
-    char        password[100];
+    char       *password = NULL;
     bool        new_pass;

     pg_logging_init(argv[0]);
@@ -233,8 +233,7 @@ main(int argc, char *argv[])
          * offer a potentially wrong one.  Typical uses of this option are
          * noninteractive anyway.
          */
-        simple_prompt("Password: ", password, sizeof(password), false);
-        have_password = true;
+        password = simple_prompt("Password: ", false);
     }

     /* loop until we have a password if requested by backend */
@@ -251,7 +250,7 @@ main(int argc, char *argv[])
         keywords[2] = "user";
         values[2] = options.username;
         keywords[3] = "password";
-        values[3] = have_password ? password : NULL;
+        values[3] = password;
         keywords[4] = "dbname"; /* see do_connect() */
         values[4] = (options.list_dbs && options.dbname == NULL) ?
             "postgres" : options.dbname;
@@ -269,7 +268,7 @@ main(int argc, char *argv[])

         if (PQstatus(pset.db) == CONNECTION_BAD &&
             PQconnectionNeedsPassword(pset.db) &&
-            !have_password &&
+            !password &&
             pset.getPassword != TRI_NO)
         {
             /*
@@ -287,9 +286,8 @@ main(int argc, char *argv[])
                 password_prompt = pg_strdup(_("Password: "));
             PQfinish(pset.db);

-            simple_prompt(password_prompt, password, sizeof(password), false);
+            password = simple_prompt(password_prompt, false);
             free(password_prompt);
-            have_password = true;
             new_pass = true;
         }
     } while (new_pass);
diff --git a/src/bin/scripts/common.c b/src/bin/scripts/common.c
index 420d0d11a5..e987eef234 100644
--- a/src/bin/scripts/common.c
+++ b/src/bin/scripts/common.c
@@ -20,6 +20,7 @@
 #include "common.h"
 #include "common/connect.h"
 #include "common/logging.h"
+#include "common/string.h"
 #include "fe_utils/cancel.h"
 #include "fe_utils/string_utils.h"

@@ -68,18 +69,17 @@ connectDatabase(const char *dbname, const char *pghost,
 {
     PGconn       *conn;
     bool        new_pass;
-    static bool have_password = false;
-    static char password[100];
+    static char *password = NULL;

-    if (!allow_password_reuse)
-        have_password = false;
-
-    if (!have_password && prompt_password == TRI_YES)
+    if (!allow_password_reuse && password)
     {
-        simple_prompt("Password: ", password, sizeof(password), false);
-        have_password = true;
+        free(password);
+        password = NULL;
     }

+    if (!password && prompt_password == TRI_YES)
+        password = simple_prompt("Password: ", false);
+
     /*
      * Start the connection.  Loop until we have a password if requested by
      * backend.
@@ -96,7 +96,7 @@ connectDatabase(const char *dbname, const char *pghost,
         keywords[2] = "user";
         values[2] = pguser;
         keywords[3] = "password";
-        values[3] = have_password ? password : NULL;
+        values[3] = password;
         keywords[4] = "dbname";
         values[4] = dbname;
         keywords[5] = "fallback_application_name";
@@ -122,8 +122,9 @@ connectDatabase(const char *dbname, const char *pghost,
             prompt_password != TRI_NO)
         {
             PQfinish(conn);
-            simple_prompt("Password: ", password, sizeof(password), false);
-            have_password = true;
+            if (password)
+                free(password);
+            password = simple_prompt("Password: ", false);
             new_pass = true;
         }
     } while (new_pass);
@@ -444,14 +445,21 @@ yesno_prompt(const char *question)

     for (;;)
     {
-        char        resp[10];
+        char       *resp;

-        simple_prompt(prompt, resp, sizeof(resp), true);
+        resp = simple_prompt(prompt, true);

         if (strcmp(resp, _(PG_YESLETTER)) == 0)
+        {
+            free(resp);
             return true;
+        }
         if (strcmp(resp, _(PG_NOLETTER)) == 0)
+        {
+            free(resp);
             return false;
+        }
+        free(resp);

         printf(_("Please answer \"%s\" or \"%s\".\n"),
                _(PG_YESLETTER), _(PG_NOLETTER));
diff --git a/src/bin/scripts/createuser.c b/src/bin/scripts/createuser.c
index 9ced079ac7..6179199563 100644
--- a/src/bin/scripts/createuser.c
+++ b/src/bin/scripts/createuser.c
@@ -13,6 +13,7 @@
 #include "postgres_fe.h"
 #include "common.h"
 #include "common/logging.h"
+#include "common/string.h"
 #include "fe_utils/simple_list.h"
 #include "fe_utils/string_utils.h"

@@ -63,8 +64,6 @@ main(int argc, char *argv[])
     int            conn_limit = -2;    /* less than minimum valid value */
     bool        pwprompt = false;
     char       *newpassword = NULL;
-    char        newuser_buf[128];
-    char        newpassword_buf[100];

     /* Tri-valued variables.  */
     enum trivalue createdb = TRI_DEFAULT,
@@ -191,9 +190,7 @@ main(int argc, char *argv[])
     {
         if (interactive)
         {
-            simple_prompt("Enter name of role to add: ",
-                          newuser_buf, sizeof(newuser_buf), true);
-            newuser = newuser_buf;
+            newuser = simple_prompt("Enter name of role to add: ", true);
         }
         else
         {
@@ -206,17 +203,16 @@ main(int argc, char *argv[])

     if (pwprompt)
     {
-        char        pw2[100];
+        char       *pw2;

-        simple_prompt("Enter password for new role: ",
-                      newpassword_buf, sizeof(newpassword_buf), false);
-        simple_prompt("Enter it again: ", pw2, sizeof(pw2), false);
-        if (strcmp(newpassword_buf, pw2) != 0)
+        newpassword = simple_prompt("Enter password for new role: ", false);
+        pw2 = simple_prompt("Enter it again: ", false);
+        if (strcmp(newpassword, pw2) != 0)
         {
             fprintf(stderr, _("Passwords didn't match.\n"));
             exit(1);
         }
-        newpassword = newpassword_buf;
+        free(pw2);
     }

     if (superuser == 0)
diff --git a/src/bin/scripts/dropuser.c b/src/bin/scripts/dropuser.c
index fee270d4f6..f7ddd1402d 100644
--- a/src/bin/scripts/dropuser.c
+++ b/src/bin/scripts/dropuser.c
@@ -13,6 +13,7 @@
 #include "postgres_fe.h"
 #include "common.h"
 #include "common/logging.h"
+#include "common/string.h"
 #include "fe_utils/string_utils.h"


@@ -47,7 +48,6 @@ main(int argc, char *argv[])
     enum trivalue prompt_password = TRI_DEFAULT;
     bool        echo = false;
     bool        interactive = false;
-    char        dropuser_buf[128];

     PQExpBufferData sql;

@@ -112,9 +112,7 @@ main(int argc, char *argv[])
     {
         if (interactive)
         {
-            simple_prompt("Enter name of role to drop: ",
-                          dropuser_buf, sizeof(dropuser_buf), true);
-            dropuser = dropuser_buf;
+            dropuser = simple_prompt("Enter name of role to drop: ", true);
         }
         else
         {
diff --git a/src/common/Makefile b/src/common/Makefile
index 16619e4ba8..ae05247631 100644
--- a/src/common/Makefile
+++ b/src/common/Makefile
@@ -92,7 +92,8 @@ OBJS_FRONTEND = \
     fe_memutils.o \
     file_utils.o \
     logging.o \
-    restricted_token.o
+    restricted_token.o \
+    sprompt.o

 # foo.o, foo_shlib.o, and foo_srv.o are all built from foo.c
 OBJS_SHLIB = $(OBJS_FRONTEND:%.o=%_shlib.o)
diff --git a/src/common/saslprep.c b/src/common/saslprep.c
index 2dedf6b0fb..d60452f75f 100644
--- a/src/common/saslprep.c
+++ b/src/common/saslprep.c
@@ -29,12 +29,6 @@
 #include "common/unicode_norm.h"
 #include "mb/pg_wchar.h"

-/*
- * Limit on how large password's we will try to process.  A password
- * larger than this will be treated the same as out-of-memory.
- */
-#define MAX_PASSWORD_LENGTH        1024
-
 /*
  * In backend, we will use palloc/pfree.  In frontend, use malloc, and
  * return SASLPREP_OOM on out-of-memory.
@@ -1078,18 +1072,6 @@ pg_saslprep(const char *input, char **output)
     /* Ensure we return *output as NULL on failure */
     *output = NULL;

-    /* Check that the password isn't stupendously long */
-    if (strlen(input) > MAX_PASSWORD_LENGTH)
-    {
-#ifndef FRONTEND
-        ereport(ERROR,
-                (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
-                 errmsg("password too long")));
-#else
-        return SASLPREP_OOM;
-#endif
-    }
-
     /*
      * Quick check if the input is pure ASCII.  An ASCII string requires no
      * further processing.
diff --git a/src/port/sprompt.c b/src/common/sprompt.c
similarity index 82%
rename from src/port/sprompt.c
rename to src/common/sprompt.c
index 6d8a8b2609..71be4903b5 100644
--- a/src/port/sprompt.c
+++ b/src/common/sprompt.c
@@ -8,12 +8,15 @@
  *
  *
  * IDENTIFICATION
- *      src/port/sprompt.c
+ *      src/common/sprompt.c
  *
  *-------------------------------------------------------------------------
  */
 #include "c.h"

+#include "common/string.h"
+#include "lib/stringinfo.h"
+
 #ifdef HAVE_TERMIOS_H
 #include <termios.h>
 #endif
@@ -26,20 +29,17 @@
  * passwords interactively.  Reads from /dev/tty or stdin/stderr.
  *
  * prompt:        The prompt to print, or NULL if none (automatically localized)
- * destination: buffer in which to store result
- * destlen:        allocated length of destination
  * echo:        Set to false if you want to hide what is entered (for passwords)
  *
- * The input (without trailing newline) is returned in the destination buffer,
- * with a '\0' appended.
+ * The input (without trailing newline) is returned as a malloc'd string.
+ * Caller is responsible for freeing it when done.
  */
-void
-simple_prompt(const char *prompt, char *destination, size_t destlen, bool echo)
+char *
+simple_prompt(const char *prompt, bool echo)
 {
-    int            length;
     FILE       *termin,
                *termout;
-
+    StringInfoData buf;
 #if defined(HAVE_TERMIOS_H)
     struct termios t_orig,
                 t;
@@ -126,29 +126,25 @@ simple_prompt(const char *prompt, char *destination, size_t destlen, bool echo)
         fflush(termout);
     }

-    if (fgets(destination, destlen, termin) == NULL)
-        destination[0] = '\0';
+    initStringInfo(&buf);

-    length = strlen(destination);
-    if (length > 0 && destination[length - 1] != '\n')
+    while (!feof(termin) && !ferror(termin))
     {
-        /* eat rest of the line */
-        char        buf[128];
-        int            buflen;
-
-        do
-        {
-            if (fgets(buf, sizeof(buf), termin) == NULL)
-                break;
-            buflen = strlen(buf);
-        } while (buflen > 0 && buf[buflen - 1] != '\n');
+        /* Make sure there's a reasonable amount of room in the buffer */
+        enlargeStringInfo(&buf, 128);
+
+        /* Read some data, appending it to what we already have */
+        if (fgets(buf.data + buf.len, buf.maxlen - buf.len, termin) == NULL)
+            break;
+        buf.len += strlen(buf.data + buf.len);
+
+        /* Done if we have a whole line, else loop to read more */
+        if (buf.len > 0 && buf.data[buf.len - 1] == '\n')
+            break;
     }

     /* strip trailing newline, including \r in case we're on Windows */
-    while (length > 0 &&
-           (destination[length - 1] == '\n' ||
-            destination[length - 1] == '\r'))
-        destination[--length] = '\0';
+    (void) pg_strip_crlf(buf.data);

     if (!echo)
     {
@@ -169,4 +165,6 @@ simple_prompt(const char *prompt, char *destination, size_t destlen, bool echo)
         fclose(termin);
         fclose(termout);
     }
+
+    return buf.data;
 }
diff --git a/src/include/common/string.h b/src/include/common/string.h
index 5113c04434..08026c8898 100644
--- a/src/include/common/string.h
+++ b/src/include/common/string.h
@@ -10,10 +10,14 @@
 #ifndef COMMON_STRING_H
 #define COMMON_STRING_H

+/* functions in src/common/string.c */
 extern bool pg_str_endswith(const char *str, const char *end);
 extern int    strtoint(const char *pg_restrict str, char **pg_restrict endptr,
                      int base);
 extern void pg_clean_ascii(char *str);
 extern int    pg_strip_crlf(char *str);

+/* functions in src/common/sprompt.c */
+extern char *simple_prompt(const char *prompt, bool echo);
+
 #endif                            /* COMMON_STRING_H */
diff --git a/src/include/port.h b/src/include/port.h
index 271ff0d00b..84bf2c363f 100644
--- a/src/include/port.h
+++ b/src/include/port.h
@@ -213,10 +213,6 @@ extern char *pg_strerror_r(int errnum, char *buf, size_t buflen);
 /* Wrap strsignal(), or provide our own version if necessary */
 extern const char *pg_strsignal(int signum);

-/* Portable prompt handling */
-extern void simple_prompt(const char *prompt, char *destination, size_t destlen,
-                          bool echo);
-
 extern int    pclose_check(FILE *stream);

 /* Global variable holding time zone information. */
diff --git a/src/port/Makefile b/src/port/Makefile
index 8defa1257b..e41b005c4f 100644
--- a/src/port/Makefile
+++ b/src/port/Makefile
@@ -35,6 +35,8 @@ include $(top_builddir)/src/Makefile.global
 override CPPFLAGS := -I$(top_builddir)/src/port -DFRONTEND $(CPPFLAGS)
 LIBS += $(PTHREAD_LIBS)

+# If you add objects here, see also src/tools/msvc/Mkvcbuild.pm
+
 OBJS = \
     $(LIBOBJS) \
     $(PG_CRC32C_OBJS) \
@@ -55,7 +57,6 @@ OBJS = \
     qsort_arg.o \
     quotes.o \
     snprintf.o \
-    sprompt.o \
     strerror.o \
     tar.o \
     thread.o
diff --git a/src/tools/msvc/Mkvcbuild.pm b/src/tools/msvc/Mkvcbuild.pm
index 20da7985c1..1a731e834f 100644
--- a/src/tools/msvc/Mkvcbuild.pm
+++ b/src/tools/msvc/Mkvcbuild.pm
@@ -102,7 +102,7 @@ sub mkvcbuild
       pread.c pwrite.c pg_bitutils.c
       pg_strong_random.c pgcheckdir.c pgmkdirp.c pgsleep.c pgstrcasecmp.c
       pqsignal.c mkdtemp.c qsort.c qsort_arg.c quotes.c system.c
-      sprompt.c strerror.c tar.c thread.c
+      strerror.c tar.c thread.c
       win32env.c win32error.c win32security.c win32setlocale.c);

     push(@pgportfiles, 'strtof.c') if ($vsVersion < '14.00');
@@ -139,7 +139,7 @@ sub mkvcbuild

     our @pgcommonfrontendfiles = (
         @pgcommonallfiles, qw(fe_memutils.c file_utils.c
-          logging.c restricted_token.c));
+          logging.c restricted_token.c sprompt.c));

     our @pgcommonbkndfiles = @pgcommonallfiles;


pgsql-hackers by date:

Previous
From: Kasahara Tatsuhito
Date:
Subject: Re: Get memory contexts of an arbitrary backend process
Next
From: Tom Lane
Date:
Subject: Re: Fix for configure error in 9.5/9.6 on macOS 11.0 Big Sur